This commit is contained in:
juancwu 2026-01-14 21:51:08 +00:00
commit dd7f2ebe3e
15 changed files with 373 additions and 70 deletions

View file

@ -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) }

View file

@ -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>
}
}
}

View file

@ -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)
}

View file

@ -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)
}
}
}

View file

@ -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)
}
}