fix: some elements are not templui components
All checks were successful
Deploy / build-and-deploy (push) Successful in 2m17s
All checks were successful
Deploy / build-and-deploy (push) Successful in 2m17s
This commit is contained in:
parent
d7cd50d671
commit
e5941e1329
7 changed files with 175 additions and 104 deletions
|
|
@ -299,18 +299,20 @@ templ ItemSelectorSection(listsWithItems []model.ListWithUncheckedItems, oob boo
|
|||
"_": "on change repeat for cb in <input[name='item_ids']/> in #" + itemsID + " set cb.checked to my.checked end",
|
||||
},
|
||||
})
|
||||
<button
|
||||
type="button"
|
||||
id={ toggleID }
|
||||
class="flex-1 flex items-center gap-1 text-sm font-medium cursor-pointer select-none"
|
||||
_={ "on click toggle .hidden on #" + itemsID + " then toggle .rotate-90 on <svg/> in me" }
|
||||
>
|
||||
@button.Button(button.Props{
|
||||
ID: toggleID,
|
||||
Variant: button.VariantGhost,
|
||||
Class: "flex-1 h-auto p-0 justify-start gap-1 text-sm font-medium select-none",
|
||||
Attributes: templ.Attributes{
|
||||
"_": "on click toggle .hidden on #" + itemsID + " then toggle .rotate-90 on <svg/> in me",
|
||||
},
|
||||
}) {
|
||||
@icon.ChevronRight(icon.Props{Size: 14})
|
||||
{ lwi.List.Name }
|
||||
<span class="text-muted-foreground">
|
||||
({ strconv.Itoa(len(lwi.Items)) })
|
||||
</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<div id={ itemsID } class="hidden pl-6 space-y-1">
|
||||
for _, item := range lwi.Items {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/input"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/label"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/radio"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox"
|
||||
)
|
||||
|
||||
func methodDisplay(m *model.PaymentMethod) string {
|
||||
|
|
@ -240,29 +241,29 @@ templ EditMethodForm(spaceID string, method *model.PaymentMethod, dialogID strin
|
|||
|
||||
templ MethodSelector(methods []*model.PaymentMethod, selectedMethodID *string) {
|
||||
<div>
|
||||
@label.Label(label.Props{For: "method-select"}) {
|
||||
@label.Label(label.Props{}) {
|
||||
Payment Method
|
||||
}
|
||||
<select
|
||||
name="payment_method_id"
|
||||
id="method-select"
|
||||
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
>
|
||||
<option value="">Cash</option>
|
||||
for _, m := range methods {
|
||||
<option
|
||||
value={ m.ID }
|
||||
if selectedMethodID != nil && *selectedMethodID == m.ID {
|
||||
selected
|
||||
}
|
||||
>
|
||||
if m.LastFour != nil {
|
||||
{ m.Name } (*{ *m.LastFour })
|
||||
} else {
|
||||
{ m.Name }
|
||||
}
|
||||
</option>
|
||||
@selectbox.SelectBox() {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "payment_method_id"}) {
|
||||
@selectbox.Value(selectbox.ValueProps{Placeholder: "Cash"})
|
||||
}
|
||||
</select>
|
||||
@selectbox.Content(selectbox.ContentProps{NoSearch: len(methods) <= 5}) {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "", Selected: selectedMethodID == nil}) {
|
||||
Cash
|
||||
}
|
||||
for _, m := range methods {
|
||||
if m.LastFour != nil {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: m.ID, Selected: selectedMethodID != nil && *selectedMethodID == m.ID}) {
|
||||
{ m.Name } (*{ *m.LastFour })
|
||||
}
|
||||
} else {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: m.ID, Selected: selectedMethodID != nil && *selectedMethodID == m.ID}) {
|
||||
{ m.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/label"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/paymentmethod"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/radio"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/tagsinput"
|
||||
)
|
||||
|
||||
|
|
@ -216,16 +217,31 @@ templ AddRecurringForm(spaceID string, tags []*model.Tag, methods []*model.Payme
|
|||
</div>
|
||||
// Frequency
|
||||
<div>
|
||||
@label.Label(label.Props{For: "recurring-frequency"}) {
|
||||
@label.Label(label.Props{}) {
|
||||
Frequency
|
||||
}
|
||||
<select name="frequency" id="recurring-frequency" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background" required>
|
||||
<option value="daily">Daily</option>
|
||||
<option value="weekly">Weekly</option>
|
||||
<option value="biweekly">Biweekly</option>
|
||||
<option value="monthly" selected>Monthly</option>
|
||||
<option value="yearly">Yearly</option>
|
||||
</select>
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "recurring-frequency"}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "frequency"}) {
|
||||
@selectbox.Value()
|
||||
}
|
||||
@selectbox.Content(selectbox.ContentProps{NoSearch: true}) {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "daily"}) {
|
||||
Daily
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "weekly"}) {
|
||||
Weekly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "biweekly"}) {
|
||||
Biweekly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "monthly", Selected: true}) {
|
||||
Monthly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "yearly"}) {
|
||||
Yearly
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
// Start Date
|
||||
<div>
|
||||
|
|
@ -345,16 +361,31 @@ templ EditRecurringForm(spaceID string, re *model.RecurringExpenseWithTagsAndMet
|
|||
</div>
|
||||
// Frequency
|
||||
<div>
|
||||
@label.Label(label.Props{For: "edit-recurring-freq-" + re.ID}) {
|
||||
@label.Label(label.Props{}) {
|
||||
Frequency
|
||||
}
|
||||
<select name="frequency" id={ "edit-recurring-freq-" + re.ID } class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background" required>
|
||||
<option value="daily" selected?={ re.Frequency == model.FrequencyDaily }>Daily</option>
|
||||
<option value="weekly" selected?={ re.Frequency == model.FrequencyWeekly }>Weekly</option>
|
||||
<option value="biweekly" selected?={ re.Frequency == model.FrequencyBiweekly }>Biweekly</option>
|
||||
<option value="monthly" selected?={ re.Frequency == model.FrequencyMonthly }>Monthly</option>
|
||||
<option value="yearly" selected?={ re.Frequency == model.FrequencyYearly }>Yearly</option>
|
||||
</select>
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "edit-recurring-freq-" + re.ID}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "frequency"}) {
|
||||
@selectbox.Value()
|
||||
}
|
||||
@selectbox.Content(selectbox.ContentProps{NoSearch: true}) {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "daily", Selected: re.Frequency == model.FrequencyDaily}) {
|
||||
Daily
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "weekly", Selected: re.Frequency == model.FrequencyWeekly}) {
|
||||
Weekly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "biweekly", Selected: re.Frequency == model.FrequencyBiweekly}) {
|
||||
Biweekly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "monthly", Selected: re.Frequency == model.FrequencyMonthly}) {
|
||||
Monthly
|
||||
}
|
||||
@selectbox.Item(selectbox.ItemProps{Value: "yearly", Selected: re.Frequency == model.FrequencyYearly}) {
|
||||
Yearly
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
// Start Date
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -58,21 +58,25 @@ templ ListCardHeader(spaceID string, list *model.ShoppingList) {
|
|||
<div id={ "lch-" + list.ID } class="flex items-center justify-between gap-2">
|
||||
<h3 class="font-semibold truncate">{ list.Name }</h3>
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="text-muted-foreground hover:text-foreground p-1 rounded hover:bg-muted transition-colors"
|
||||
_={ fmt.Sprintf("on click toggle .hidden on #lch-%s then toggle .hidden on #lche-%s then focus() the first <input/> in #lche-%s", list.ID, list.ID, list.ID) }
|
||||
>
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantGhost,
|
||||
Size: button.SizeIcon,
|
||||
Class: "size-7 text-muted-foreground hover:text-foreground",
|
||||
Attributes: templ.Attributes{
|
||||
"_": fmt.Sprintf("on click toggle .hidden on #lch-%s then toggle .hidden on #lche-%s then focus() the first <input/> in #lche-%s", list.ID, list.ID, list.ID),
|
||||
},
|
||||
}) {
|
||||
@icon.Pencil(icon.Props{Size: 14})
|
||||
</button>
|
||||
}
|
||||
@dialog.Dialog(dialog.Props{ID: "del-list-" + list.ID}) {
|
||||
@dialog.Trigger() {
|
||||
<button
|
||||
type="button"
|
||||
class="text-muted-foreground hover:text-destructive p-1 rounded hover:bg-muted transition-colors"
|
||||
>
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantGhost,
|
||||
Size: button.SizeIcon,
|
||||
Class: "size-7 text-muted-foreground hover:text-destructive",
|
||||
}) {
|
||||
@icon.Trash2(icon.Props{Size: 14})
|
||||
</button>
|
||||
}
|
||||
}
|
||||
@dialog.Content() {
|
||||
@dialog.Header() {
|
||||
|
|
@ -121,16 +125,18 @@ templ ListCardHeader(spaceID string, list *model.ShoppingList) {
|
|||
"required": "true",
|
||||
},
|
||||
})
|
||||
<button type="submit" class="inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 bg-primary text-primary-foreground hover:bg-primary/90">
|
||||
@button.Submit(button.Props{Size: button.SizeSm}) {
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 border hover:bg-muted"
|
||||
_={ fmt.Sprintf("on click toggle .hidden on #lche-%s then toggle .hidden on #lch-%s", list.ID, list.ID) }
|
||||
>
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantOutline,
|
||||
Size: button.SizeSm,
|
||||
Attributes: templ.Attributes{
|
||||
"_": fmt.Sprintf("on click toggle .hidden on #lche-%s then toggle .hidden on #lch-%s", list.ID, list.ID),
|
||||
},
|
||||
}) {
|
||||
Cancel
|
||||
</button>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
|
||||
|
|
@ -203,15 +209,18 @@ templ CardItemDetail(spaceID string, item *model.ListItem) {
|
|||
},
|
||||
})
|
||||
<span class={ "text-sm flex-1", templ.KV("line-through text-muted-foreground", item.IsChecked) }>{ item.Name }</span>
|
||||
<button
|
||||
type="button"
|
||||
class="text-muted-foreground hover:text-destructive p-1 rounded shrink-0"
|
||||
hx-delete={ fmt.Sprintf("/app/spaces/%s/lists/%s/items/%s", spaceID, item.ListID, item.ID) }
|
||||
hx-swap="none"
|
||||
_={ fmt.Sprintf("on htmx:afterRequest send refreshItems to #list-items-%s", item.ListID) }
|
||||
>
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantGhost,
|
||||
Size: button.SizeIcon,
|
||||
Class: "size-7 text-muted-foreground hover:text-destructive shrink-0",
|
||||
Attributes: templ.Attributes{
|
||||
"hx-delete": fmt.Sprintf("/app/spaces/%s/lists/%s/items/%s", spaceID, item.ListID, item.ID),
|
||||
"hx-swap": "none",
|
||||
"_": fmt.Sprintf("on htmx:afterRequest send refreshItems to #list-items-%s", item.ListID),
|
||||
},
|
||||
}) {
|
||||
@icon.X(icon.Props{Size: 14})
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -219,12 +228,16 @@ templ CardItemDetail(spaceID string, item *model.ListItem) {
|
|||
templ ListNameHeader(spaceID string, list *model.ShoppingList) {
|
||||
<div id="list-name-header" class="flex items-center gap-2 group">
|
||||
<h1 class="text-2xl font-bold">{ list.Name }</h1>
|
||||
<button
|
||||
class="text-muted-foreground hover:text-foreground opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
_="on click toggle .hidden on #list-name-header then toggle .hidden on #list-name-edit then focus() the first <input/> in #list-name-edit"
|
||||
>
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantGhost,
|
||||
Size: button.SizeIcon,
|
||||
Class: "size-7 text-muted-foreground hover:text-foreground opacity-0 group-hover:opacity-100 transition-opacity",
|
||||
Attributes: templ.Attributes{
|
||||
"_": "on click toggle .hidden on #list-name-header then toggle .hidden on #list-name-edit then focus() the first <input/> in #list-name-edit",
|
||||
},
|
||||
}) {
|
||||
@icon.Pencil(icon.Props{Size: 16})
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<form
|
||||
id="list-name-edit"
|
||||
|
|
@ -243,16 +256,17 @@ templ ListNameHeader(spaceID string, list *model.ShoppingList) {
|
|||
"required": "true",
|
||||
},
|
||||
})
|
||||
<button type="submit" class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 bg-primary text-primary-foreground hover:bg-primary/90">
|
||||
@button.Submit() {
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 border hover:bg-muted"
|
||||
_="on click toggle .hidden on #list-name-edit then toggle .hidden on #list-name-header"
|
||||
>
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantOutline,
|
||||
Attributes: templ.Attributes{
|
||||
"_": "on click toggle .hidden on #list-name-edit then toggle .hidden on #list-name-header",
|
||||
},
|
||||
}) {
|
||||
Cancel
|
||||
</button>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
|
||||
|
|
@ -270,13 +284,17 @@ templ ItemDetail(spaceID string, item *model.ListItem) {
|
|||
},
|
||||
})
|
||||
<span class={ templ.KV("line-through text-muted-foreground", item.IsChecked) }>{ item.Name }</span>
|
||||
<button
|
||||
hx-delete={ fmt.Sprintf("/app/spaces/%s/lists/%s/items/%s", spaceID, item.ListID, item.ID) }
|
||||
hx-target={ "#item-" + item.ID }
|
||||
hx-swap="outerHTML"
|
||||
class="ml-auto btn btn-xs btn-ghost"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
@button.Button(button.Props{
|
||||
Variant: button.VariantGhost,
|
||||
Size: button.SizeIcon,
|
||||
Class: "ml-auto size-7",
|
||||
Attributes: templ.Attributes{
|
||||
"hx-delete": fmt.Sprintf("/app/spaces/%s/lists/%s/items/%s", spaceID, item.ListID, item.ID),
|
||||
"hx-target": "#item-" + item.ID,
|
||||
"hx-swap": "outerHTML",
|
||||
},
|
||||
}) {
|
||||
@icon.X(icon.Props{Size: 14})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/components/toast"
|
|||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/calendar"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/datepicker"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/progress"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/tagsinput"
|
||||
import "fmt"
|
||||
import "time"
|
||||
|
|
@ -51,6 +52,7 @@ templ Base(props ...SEOProps) {
|
|||
@datepicker.Script()
|
||||
@progress.Script()
|
||||
@tagsinput.Script()
|
||||
@selectbox.Script()
|
||||
// Site-wide enhancements
|
||||
@themeScript()
|
||||
// Must run before body to prevent flash
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/input"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/label"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/radio"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/layouts"
|
||||
)
|
||||
|
||||
|
|
@ -178,15 +179,21 @@ templ AddBudgetForm(spaceID string, tags []*model.Tag) {
|
|||
@csrf.Token()
|
||||
// Tag selector
|
||||
<div>
|
||||
@label.Label(label.Props{For: "budget-tag"}) {
|
||||
@label.Label(label.Props{}) {
|
||||
Tag
|
||||
}
|
||||
<select name="tag_id" id="budget-tag" class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background" required>
|
||||
<option value="" disabled selected>Select a tag...</option>
|
||||
for _, t := range tags {
|
||||
<option value={ t.ID }>{ t.Name }</option>
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "budget-tag"}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_id"}) {
|
||||
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select a tag..."})
|
||||
}
|
||||
</select>
|
||||
@selectbox.Content() {
|
||||
for _, t := range tags {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: t.ID}) {
|
||||
{ t.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
// Amount
|
||||
<div>
|
||||
|
|
@ -280,14 +287,21 @@ templ EditBudgetForm(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag
|
|||
@csrf.Token()
|
||||
// Tag selector
|
||||
<div>
|
||||
@label.Label(label.Props{For: "edit-budget-tag-" + b.ID}) {
|
||||
@label.Label(label.Props{}) {
|
||||
Tag
|
||||
}
|
||||
<select name="tag_id" id={ "edit-budget-tag-" + b.ID } class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background" required>
|
||||
for _, t := range tags {
|
||||
<option value={ t.ID } selected?={ t.ID == b.TagID }>{ t.Name }</option>
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "edit-budget-tag-" + b.ID}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_id"}) {
|
||||
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select a tag..."})
|
||||
}
|
||||
</select>
|
||||
@selectbox.Content() {
|
||||
for _, t := range tags {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: t.ID, Selected: t.ID == b.TagID}) {
|
||||
{ t.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
// Amount
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package pages
|
|||
import (
|
||||
"fmt"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/model"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/badge"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/button"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/dialog"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/expense"
|
||||
|
|
@ -74,7 +75,9 @@ templ SpaceOverviewPage(space *model.Space, lists []*model.ShoppingList, tags []
|
|||
if len(tags) > 0 {
|
||||
<div class="flex flex-wrap gap-2">
|
||||
for _, tag := range tags {
|
||||
<span class="bg-secondary text-secondary-foreground rounded-full px-3 py-1 text-sm">{ tag.Name }</span>
|
||||
@badge.Badge(badge.Props{Variant: badge.VariantSecondary}) {
|
||||
{ tag.Name }
|
||||
}
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue