add SSE
This commit is contained in:
parent
4d6e6799a0
commit
dd7f2ebe3e
15 changed files with 373 additions and 70 deletions
|
|
@ -84,8 +84,15 @@ templ AddExpenseForm(space *model.Space, tags []*model.Tag, lists []*model.Shopp
|
|||
</form>
|
||||
}
|
||||
|
||||
templ BalanceCard(balance int, oob bool) {
|
||||
<div id="balance-card" class="border rounded-lg p-4 bg-card text-card-foreground" hx-swap-oob?={ oob }>
|
||||
templ BalanceCard(spaceID string, balance int, oob bool) {
|
||||
<div
|
||||
id="balance-card"
|
||||
class="border rounded-lg p-4 bg-card text-card-foreground"
|
||||
hx-swap-oob?={ oob }
|
||||
hx-get={ "/app/spaces/" + spaceID + "/components/balance" }
|
||||
hx-trigger="sse:balance_changed"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<h2 class="text-lg font-semibold">Current Balance</h2>
|
||||
<p class={ "text-3xl font-bold", templ.KV("text-destructive", balance < 0) }>
|
||||
{ fmt.Sprintf("$%.2f", float64(balance)/100.0) }
|
||||
|
|
|
|||
|
|
@ -93,42 +93,44 @@ templ Space(title string, space *model.Space) {
|
|||
}
|
||||
}
|
||||
@sidebar.Inset() {
|
||||
// Top Navigation Bar
|
||||
<header class="sticky top-0 z-10 border-b bg-background">
|
||||
<div class="flex h-14 items-center px-6">
|
||||
<div class="flex items-center gap-4">
|
||||
@sidebar.Trigger()
|
||||
@breadcrumb.Breadcrumb() {
|
||||
@breadcrumb.List() {
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Link(breadcrumb.LinkProps{Href: "/app/dashboard"}) {
|
||||
Home
|
||||
<div hx-sse={ "connect:/app/spaces/" + space.ID + "/stream" } class="flex flex-col h-full">
|
||||
// Top Navigation Bar
|
||||
<header class="sticky top-0 z-10 border-b bg-background">
|
||||
<div class="flex h-14 items-center px-6">
|
||||
<div class="flex items-center gap-4">
|
||||
@sidebar.Trigger()
|
||||
@breadcrumb.Breadcrumb() {
|
||||
@breadcrumb.List() {
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Link(breadcrumb.LinkProps{Href: "/app/dashboard"}) {
|
||||
Home
|
||||
}
|
||||
}
|
||||
}
|
||||
@breadcrumb.Separator()
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Link(breadcrumb.LinkProps{Href: "/app/spaces/" + space.ID}) {
|
||||
{ space.Name }
|
||||
@breadcrumb.Separator()
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Link(breadcrumb.LinkProps{Href: "/app/spaces/" + space.ID}) {
|
||||
{ space.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
@breadcrumb.Separator()
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Page() {
|
||||
{ title }
|
||||
@breadcrumb.Separator()
|
||||
@breadcrumb.Item() {
|
||||
@breadcrumb.Page() {
|
||||
{ title }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="ml-auto flex items-center gap-4">
|
||||
@blocks.ThemeSwitcher()
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-auto flex items-center gap-4">
|
||||
@blocks.ThemeSwitcher()
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
// App Content
|
||||
<main class="flex-1 p-6">
|
||||
{ children... }
|
||||
</main>
|
||||
</header>
|
||||
// App Content
|
||||
<main class="flex-1 p-6">
|
||||
{ children... }
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,24 +33,34 @@ templ SpaceExpensesPage(space *model.Space, expenses []*model.Expense, balance i
|
|||
</div>
|
||||
|
||||
// Balance Card
|
||||
@expense.BalanceCard(balance, false)
|
||||
@expense.BalanceCard(space.ID, balance, false)
|
||||
|
||||
// List of expenses
|
||||
<div id="expenses-list" class="border rounded-lg">
|
||||
<h2 class="text-lg font-semibold p-4">History</h2>
|
||||
<div class="divide-y">
|
||||
if len(expenses) == 0 {
|
||||
<p class="p-4 text-sm text-muted-foreground">No expenses recorded yet.</p>
|
||||
}
|
||||
for _, expense := range expenses {
|
||||
@ExpenseListItem(expense)
|
||||
}
|
||||
</div>
|
||||
<div
|
||||
id="expenses-list"
|
||||
class="border rounded-lg"
|
||||
hx-get={ "/app/spaces/" + space.ID + "/components/expenses" }
|
||||
hx-trigger="sse:expenses_updated"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
@ExpensesListContent(expenses)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ ExpensesListContent(expenses []*model.Expense) {
|
||||
<h2 class="text-lg font-semibold p-4">History</h2>
|
||||
<div class="divide-y">
|
||||
if len(expenses) == 0 {
|
||||
<p class="p-4 text-sm text-muted-foreground">No expenses recorded yet.</p>
|
||||
}
|
||||
for _, expense := range expenses {
|
||||
@ExpenseListItem(expense)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
templ ExpenseListItem(expense *model.Expense) {
|
||||
<div class="p-4 flex justify-between items-center">
|
||||
<div>
|
||||
|
|
@ -73,5 +83,5 @@ templ ExpenseListItem(expense *model.Expense) {
|
|||
|
||||
templ ExpenseCreatedResponse(newExpense *model.Expense, balance int) {
|
||||
@ExpenseListItem(newExpense)
|
||||
@expense.BalanceCard(balance, true)
|
||||
@expense.BalanceCard(newExpense.SpaceID, balance, true)
|
||||
}
|
||||
|
|
@ -31,15 +31,25 @@ templ SpaceListDetailPage(space *model.Space, list *model.ShoppingList, items []
|
|||
Add Item
|
||||
}
|
||||
</form>
|
||||
<div id="items-container" class="border rounded-lg">
|
||||
if len(items) == 0 {
|
||||
<p class="text-center text-muted-foreground p-8">This list is empty.</p>
|
||||
} else {
|
||||
for _, item := range items {
|
||||
@shoppinglist.ItemDetail(space.ID, item)
|
||||
}
|
||||
}
|
||||
<div
|
||||
id="items-container"
|
||||
class="border rounded-lg"
|
||||
hx-get={ "/app/spaces/" + space.ID + "/lists/" + list.ID + "/items" }
|
||||
hx-trigger="sse:item_added, sse:item_updated, sse:item_deleted"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
@ShoppingListItems(space.ID, items)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ ShoppingListItems(spaceID string, items []*model.ListItem) {
|
||||
if len(items) == 0 {
|
||||
<p class="text-center text-muted-foreground p-8">This list is empty.</p>
|
||||
} else {
|
||||
for _, item := range items {
|
||||
@shoppinglist.ItemDetail(spaceID, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,21 @@ templ SpaceListsPage(space *model.Space, lists []*model.ShoppingList) {
|
|||
Create
|
||||
}
|
||||
</form>
|
||||
<div id="lists-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
for _, list := range lists {
|
||||
@shoppinglist.ListItem(list)
|
||||
}
|
||||
<div
|
||||
id="lists-container"
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
||||
hx-get={ "/app/spaces/" + space.ID + "/components/lists" }
|
||||
hx-trigger="sse:list_created, sse:list_deleted"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
@ListsContainer(lists)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ ListsContainer(lists []*model.ShoppingList) {
|
||||
for _, list := range lists {
|
||||
@shoppinglist.ListItem(list)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue