fix: no proper loading feedback on forms
This commit is contained in:
parent
cbb14ffba2
commit
d224f5a10a
27 changed files with 192 additions and 57 deletions
|
|
@ -164,4 +164,30 @@
|
|||
"rlig" 1,
|
||||
"calt" 1;
|
||||
}
|
||||
|
||||
/* HTMX submit button loading states */
|
||||
.htmx-submit-btn .btn-spinner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.htmx-request .htmx-submit-btn .btn-label,
|
||||
.htmx-request.htmx-submit-btn .btn-label {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.htmx-request .htmx-submit-btn .btn-spinner,
|
||||
.htmx-request.htmx-submit-btn .btn-spinner {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.htmx-request .htmx-submit-btn,
|
||||
.htmx-request.htmx-submit-btn {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
assets/js/form-submit.js
Normal file
8
assets/js/form-submit.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.addEventListener('submit', function(e) {
|
||||
var btn = e.target.querySelector('.htmx-submit-btn');
|
||||
if (btn) {
|
||||
e.target.classList.add('htmx-request');
|
||||
}
|
||||
});
|
||||
});
|
||||
4
go.mod
4
go.mod
|
|
@ -4,7 +4,7 @@ go 1.25.1
|
|||
|
||||
require (
|
||||
github.com/Oudwins/tailwind-merge-go v0.2.1
|
||||
github.com/a-h/templ v0.3.977
|
||||
github.com/a-h/templ v0.3.960
|
||||
github.com/alexedwards/argon2id v1.0.0
|
||||
github.com/emersion/go-imap v1.2.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
|
|
@ -62,7 +62,7 @@ require (
|
|||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/templui/templui v1.5.0 // indirect
|
||||
github.com/templui/templui v1.0.0 // indirect
|
||||
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect
|
||||
github.com/vertica/vertica-sql-go v1.3.3 // indirect
|
||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 // indirect
|
||||
|
|
|
|||
5
go.sum
5
go.sum
|
|
@ -23,6 +23,8 @@ github.com/Oudwins/tailwind-merge-go v0.2.1 h1:jxRaEqGtwwwF48UuFIQ8g8XT7YSualNuG
|
|||
github.com/Oudwins/tailwind-merge-go v0.2.1/go.mod h1:kkZodgOPvZQ8f7SIrlWkG/w1g9JTbtnptnePIh3V72U=
|
||||
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
|
||||
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
|
||||
github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM=
|
||||
github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
||||
github.com/a-h/templ v0.3.977 h1:kiKAPXTZE2Iaf8JbtM21r54A8bCNsncrfnokZZSrSDg=
|
||||
github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
||||
github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
|
||||
|
|
@ -148,6 +150,7 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
|
|||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
|
@ -215,6 +218,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/templui/templui v1.0.0 h1:nsCh+tTL8U9rhh0hpwkvDpiDCPP43aoBB85TLgCh/Kg=
|
||||
github.com/templui/templui v1.0.0/go.mod h1:SnKmOIs7t/ngsdWUws97CVodbz89ne9kQv3ivgdhiHo=
|
||||
github.com/templui/templui v1.5.0 h1:nLWZVCEH/Mh86ZSzqMMa3Blpq+oXQKZWIM2rJ33yHQI=
|
||||
github.com/templui/templui v1.5.0/go.mod h1:9CP7NRm+tXEA6K3/KRny+yANApKCjwXvdR8ahyfglgM=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
|
|
|
|||
|
|
@ -122,14 +122,14 @@ func (h *authHandler) SendMagicLink(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if r.URL.Query().Get("resend") == "true" {
|
||||
ui.RenderOOB(w, r, toast.Toast(toast.Props{
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Magic link sent",
|
||||
Description: "Check your email for a new magic link",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}), "beforeend:#toast-container")
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"git.juancwu.dev/juancwu/budgit/internal/ctxkeys"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/service"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/toast"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/pages"
|
||||
)
|
||||
|
||||
|
|
@ -69,6 +70,13 @@ func (h *settingsHandler) SetPassword(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Password set successfully — render page with success message
|
||||
// Password set successfully — render page with success toast
|
||||
ui.Render(w, r, pages.AppSettings(true, ""))
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Password updated",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,6 +215,13 @@ func (h *SpaceHandler) DeleteList(w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set("HX-Redirect", "/app/spaces/"+spaceID+"/lists")
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "List deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) ListPage(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -337,6 +344,13 @@ func (h *SpaceHandler) DeleteItem(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Item deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) TagsPage(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -393,6 +407,13 @@ func (h *SpaceHandler) DeleteTag(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Tag deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) ExpensesPage(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -783,6 +804,13 @@ func (h *SpaceHandler) DeleteExpense(w http.ResponseWriter, r *http.Request) {
|
|||
balance -= totalAllocated
|
||||
|
||||
ui.Render(w, r, expense.BalanceCard(spaceID, balance, totalAllocated, true))
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Expense deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) CreateInvite(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -807,7 +835,7 @@ func (h *SpaceHandler) CreateInvite(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
ui.Render(w, r, toast.Toast(toast.Props{
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Invitation sent",
|
||||
Description: "An email has been sent to " + email,
|
||||
Variant: toast.VariantSuccess,
|
||||
|
|
@ -1035,6 +1063,13 @@ func (h *SpaceHandler) RemoveMember(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Member removed",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) CancelInvite(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -1060,6 +1095,13 @@ func (h *SpaceHandler) CancelInvite(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Invitation cancelled",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) GetPendingInvites(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -1240,6 +1282,13 @@ func (h *SpaceHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
ui.Render(w, r, moneyaccount.BalanceSummaryCard(spaceID, totalBalance, totalBalance-totalAllocated, true))
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Account deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) CreateTransfer(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -1372,6 +1421,13 @@ func (h *SpaceHandler) DeleteTransfer(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
ui.Render(w, r, moneyaccount.AccountCard(spaceID, &acctWithBalance, true))
|
||||
ui.Render(w, r, moneyaccount.BalanceSummaryCard(spaceID, totalBalance, totalBalance-totalAllocated, true))
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Transfer deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
// --- Payment Methods ---
|
||||
|
|
@ -1484,6 +1540,13 @@ func (h *SpaceHandler) DeletePaymentMethod(w http.ResponseWriter, r *http.Reques
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Payment method deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
// --- Recurring Expenses ---
|
||||
|
|
@ -1787,6 +1850,13 @@ func (h *SpaceHandler) DeleteRecurringExpense(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Recurring expense deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) ToggleRecurringExpense(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -2002,6 +2072,13 @@ func (h *SpaceHandler) DeleteBudget(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
ui.RenderToast(w, r, toast.Toast(toast.Props{
|
||||
Title: "Budget deleted",
|
||||
Variant: toast.VariantSuccess,
|
||||
Icon: true,
|
||||
Dismissible: true,
|
||||
Duration: 5000,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) GetBudgetsList(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ type ExpenseItem struct {
|
|||
}
|
||||
|
||||
type TagExpenseSummary struct {
|
||||
TagID string `db:"tag_id"`
|
||||
TagName string `db:"tag_name"`
|
||||
TagID string `db:"tag_id"`
|
||||
TagName string `db:"tag_name"`
|
||||
TagColor *string `db:"tag_color"`
|
||||
TotalAmount int `db:"total_amount"`
|
||||
TotalAmount int `db:"total_amount"`
|
||||
}
|
||||
|
|
|
|||
22
internal/ui/components/button/submit.templ
Normal file
22
internal/ui/components/button/submit.templ
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package button
|
||||
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon"
|
||||
|
||||
templ Submit(props ...Props) {
|
||||
{{ var p Props }}
|
||||
if len(props) > 0 {
|
||||
{{ p = props[0] }}
|
||||
}
|
||||
if p.Type == "" {
|
||||
{{ p.Type = TypeSubmit }}
|
||||
}
|
||||
{{ p.Class = p.Class + " htmx-submit-btn" }}
|
||||
@Button(p) {
|
||||
<span class="btn-label contents">
|
||||
{ children... }
|
||||
</span>
|
||||
<span class="btn-spinner">
|
||||
@icon.LoaderCircle(icon.Props{Class: "animate-spin"})
|
||||
</span>
|
||||
}
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ templ AddExpenseForm(props AddExpenseFormProps) {
|
|||
// Shopping list items selector
|
||||
@ItemSelectorSection(props.ListsWithItems, false)
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
@ -267,7 +267,7 @@ templ EditExpenseForm(spaceID string, exp *model.ExpenseWithTagsAndMethod, metho
|
|||
// Payment Method
|
||||
@paymentmethod.MethodSelector(methods, exp.PaymentMethodID)
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ templ CreateAccountForm(spaceID string, dialogID string) {
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Create
|
||||
}
|
||||
</div>
|
||||
|
|
@ -212,7 +212,7 @@ templ EditAccountForm(spaceID string, acct *model.MoneyAccount, dialogID string)
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
@ -253,7 +253,7 @@ templ TransferForm(spaceID string, accountID string, direction model.TransferDir
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
if direction == model.TransferDirectionDeposit {
|
||||
Deposit
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ templ CreateMethodForm(spaceID string, dialogID string) {
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Create
|
||||
}
|
||||
</div>
|
||||
|
|
@ -231,7 +231,7 @@ templ EditMethodForm(spaceID string, method *model.PaymentMethod, dialogID strin
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ templ AddRecurringForm(spaceID string, tags []*model.Tag, methods []*model.Payme
|
|||
// Payment Method
|
||||
@paymentmethod.MethodSelector(methods, nil)
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
@ -401,7 +401,7 @@ templ EditRecurringForm(spaceID string, re *model.RecurringExpenseWithTagsAndMet
|
|||
// Payment Method
|
||||
@paymentmethod.MethodSelector(methods, re.PaymentMethodID)
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ templ ListCard(spaceID string, list *model.ShoppingList, items []*model.ListItem
|
|||
"autocomplete": "off",
|
||||
},
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Size: button.SizeSm,
|
||||
}) {
|
||||
@icon.Plus(icon.Props{Size: 16})
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ templ Base(props ...SEOProps) {
|
|||
@smoothScrollScript()
|
||||
// HTMX CSRF configuration
|
||||
@htmxCSRFScript()
|
||||
// Form submit spinner for non-HTMX forms
|
||||
@formSubmitScript()
|
||||
// Google Analytics
|
||||
if cfg := ctxkeys.Config(ctx); cfg != nil && cfg.GoogleMeasuringID != "" {
|
||||
@googleAnalyticsScript(cfg.GoogleMeasuringID)
|
||||
|
|
@ -118,6 +120,10 @@ templ htmxCSRFScript() {
|
|||
<script src="/assets/js/htmx-csrf.js"></script>
|
||||
}
|
||||
|
||||
templ formSubmitScript() {
|
||||
<script src="/assets/js/form-submit.js"></script>
|
||||
}
|
||||
|
||||
templ googleAnalyticsScript(id string) {
|
||||
<script async src={ "https://www.googletagmanager.com/gtag/js?id=" + id }></script>
|
||||
<script type="text/javascript">
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ templ Dashboard(spaces []*model.Space) {
|
|||
Cancel
|
||||
}
|
||||
}
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Create
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,9 +89,7 @@ templ AppSettings(hasPassword bool, errorMsg string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
if hasPassword {
|
||||
Change Password
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ templ AddBudgetForm(spaceID string, tags []*model.Tag) {
|
|||
})
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
@ -374,7 +374,7 @@ templ EditBudgetForm(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag
|
|||
}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@button.Button(button.Props{Type: button.TypeSubmit}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ templ SpaceListDetailPage(space *model.Space, list *model.ShoppingList, items []
|
|||
"autocomplete": "off",
|
||||
},
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
Add Item
|
||||
}
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ templ SpaceListsPage(space *model.Space, cards []model.ListCardData) {
|
|||
Name: "name",
|
||||
Placeholder: "New list name...",
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
Create
|
||||
}
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ templ SpaceSettingsPage(space *model.Space, members []*model.SpaceMemberWithProf
|
|||
"required": true,
|
||||
},
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
Save
|
||||
}
|
||||
</form>
|
||||
|
|
@ -110,9 +108,7 @@ templ SpaceSettingsPage(space *model.Space, members []*model.SpaceMemberWithProf
|
|||
"required": true,
|
||||
},
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
@icon.UserPlus(icon.Props{Class: "size-4"})
|
||||
Invite
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,7 @@ templ SpaceTagsPage(space *model.Space, tags []*model.Tag) {
|
|||
"autocomplete": "off",
|
||||
},
|
||||
})
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
@button.Submit() {
|
||||
Create
|
||||
}
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -57,8 +57,7 @@ templ Auth(errorMsg string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
FullWidth: true,
|
||||
}) {
|
||||
Continue with Email
|
||||
|
|
|
|||
|
|
@ -39,10 +39,9 @@ templ MagicLinkSent(email string) {
|
|||
>
|
||||
@csrf.Token()
|
||||
<input type="hidden" name="email" value={ email }/>
|
||||
@button.Button(button.Props{
|
||||
@button.Submit(button.Props{
|
||||
Variant: button.VariantOutline,
|
||||
FullWidth: true,
|
||||
Type: button.TypeSubmit,
|
||||
}) {
|
||||
Resend magic link
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,8 +76,7 @@ templ AuthPassword(errorMsg string) {
|
|||
</a>
|
||||
</div>
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
FullWidth: true,
|
||||
}) {
|
||||
Sign In
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ templ OnboardingWelcome() {
|
|||
<form action="/auth/logout" method="POST" class="text-center mt-6">
|
||||
@csrf.Token()
|
||||
<span class="text-sm text-muted-foreground">Not you? </span>
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Variant: button.VariantLink,
|
||||
Class: "p-0 h-auto text-sm",
|
||||
}) {
|
||||
|
|
@ -138,8 +137,7 @@ templ OnboardingName(errorMsg string) {
|
|||
@icon.ArrowLeft()
|
||||
Back
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Class: "grow",
|
||||
}) {
|
||||
Continue
|
||||
|
|
@ -150,8 +148,7 @@ templ OnboardingName(errorMsg string) {
|
|||
<form action="/auth/logout" method="POST" class="text-center mt-6">
|
||||
@csrf.Token()
|
||||
<span class="text-sm text-muted-foreground">Not you? </span>
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Variant: button.VariantLink,
|
||||
Class: "p-0 h-auto text-sm",
|
||||
}) {
|
||||
|
|
@ -222,8 +219,7 @@ templ OnboardingSpace(name string, errorMsg string) {
|
|||
@icon.ArrowLeft()
|
||||
Back
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Class: "grow",
|
||||
}) {
|
||||
Create Space
|
||||
|
|
@ -233,8 +229,7 @@ templ OnboardingSpace(name string, errorMsg string) {
|
|||
<form action="/auth/logout" method="POST" class="text-center mt-6">
|
||||
@csrf.Token()
|
||||
<span class="text-sm text-muted-foreground">Not you? </span>
|
||||
@button.Button(button.Props{
|
||||
Type: button.TypeSubmit,
|
||||
@button.Submit(button.Props{
|
||||
Variant: button.VariantLink,
|
||||
Class: "p-0 h-auto text-sm",
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ func RenderFragment(w http.ResponseWriter, r *http.Request, c templ.Component, f
|
|||
}
|
||||
}
|
||||
|
||||
func RenderToast(w http.ResponseWriter, r *http.Request, c templ.Component) {
|
||||
RenderOOB(w, r, c, "beforeend:#toast-container")
|
||||
}
|
||||
|
||||
func RenderOOB(w http.ResponseWriter, r *http.Request, c templ.Component, target string) {
|
||||
// Write OOB wrapper start
|
||||
_, err := fmt.Fprintf(w, `<div hx-swap-oob="%s">`, target)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue