feat: allow multi tags for budgets

This commit is contained in:
juancwu 2026-02-17 15:20:49 +00:00
commit 55e04c9b94
7 changed files with 268 additions and 80 deletions

View file

@ -37,6 +37,15 @@ func progressBarColor(status model.BudgetStatus) string {
}
}
func budgetTagSelected(tags []*model.Tag, tagID string) bool {
for _, t := range tags {
if t.ID == tagID {
return true
}
}
return false
}
templ SpaceBudgetsPage(space *model.Space, budgets []*model.BudgetWithSpent, tags []*model.Tag) {
@layouts.Space("Budgets", space) {
<div class="space-y-4">
@ -54,7 +63,7 @@ templ SpaceBudgetsPage(space *model.Space, budgets []*model.BudgetWithSpent, tag
Add Budget
}
@dialog.Description() {
Set a spending limit for a tag category.
Set a spending limit for one or more tag categories.
}
}
@AddBudgetForm(space.ID, tags)
@ -89,11 +98,15 @@ templ BudgetCard(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag) {
<div id={ "budget-" + b.ID } class="border rounded-lg p-4 bg-card text-card-foreground space-y-3">
<div class="flex justify-between items-start">
<div>
<div class="flex items-center gap-2">
if b.TagColor != nil {
<span class="inline-block w-3 h-3 rounded-full" style={ "background-color: " + *b.TagColor }></span>
<div class="flex items-center gap-2 flex-wrap">
for _, t := range b.Tags {
<span class="inline-flex items-center gap-1">
if t.Color != nil {
<span class="inline-block w-3 h-3 rounded-full" style={ "background-color: " + *t.Color }></span>
}
<span class="text-sm font-semibold">{ t.Name }</span>
</span>
}
<h3 class="font-semibold">{ b.TagName }</h3>
</div>
<p class="text-xs text-muted-foreground">{ periodLabel(b.Period) } budget</p>
</div>
@ -128,7 +141,7 @@ templ BudgetCard(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag) {
Delete Budget
}
@dialog.Description() {
Are you sure you want to delete the budget for "{ b.TagName }"?
Are you sure you want to delete this budget?
}
}
@dialog.Footer() {
@ -177,14 +190,14 @@ templ AddBudgetForm(spaceID string, tags []*model.Tag) {
class="space-y-4"
>
@csrf.Token()
// Tag selector
// Tag selector (multi-select)
<div>
@label.Label(label.Props{}) {
Tag
Tags
}
@selectbox.SelectBox(selectbox.Props{ID: "budget-tag"}) {
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_id"}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select a tag..."})
@selectbox.SelectBox(selectbox.Props{ID: "budget-tags", Multiple: true}) {
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_ids", Multiple: true, ShowPills: true, SelectedCountText: "{n} tags selected"}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select tags..."})
}
@selectbox.Content() {
for _, t := range tags {
@ -285,18 +298,18 @@ templ EditBudgetForm(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag
class="space-y-4"
>
@csrf.Token()
// Tag selector
// Tag selector (multi-select with pre-selected tags)
<div>
@label.Label(label.Props{}) {
Tag
Tags
}
@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..."})
@selectbox.SelectBox(selectbox.Props{ID: "edit-budget-tags-" + b.ID, Multiple: true}) {
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_ids", Multiple: true, ShowPills: true, SelectedCountText: "{n} tags selected"}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select tags..."})
}
@selectbox.Content() {
for _, t := range tags {
@selectbox.Item(selectbox.ItemProps{Value: t.ID, Selected: t.ID == b.TagID}) {
@selectbox.Item(selectbox.ItemProps{Value: t.ID, Selected: budgetTagSelected(b.Tags, t.ID)}) {
{ t.Name }
}
}

View file

@ -257,11 +257,15 @@ templ overviewBudgetsCard(data OverviewData) {
{{ pct = 100 }}
}
<div class="space-y-1">
<div class="flex items-center gap-2">
if b.TagColor != nil {
<span class="inline-block w-2.5 h-2.5 rounded-full" style={ "background-color: " + *b.TagColor }></span>
<div class="flex items-center gap-2 flex-wrap">
for _, t := range b.Tags {
<span class="inline-flex items-center gap-1">
if t.Color != nil {
<span class="inline-block w-2.5 h-2.5 rounded-full" style={ "background-color: " + *t.Color }></span>
}
<span class="text-sm font-medium">{ t.Name }</span>
</span>
}
<span class="text-sm font-medium">{ b.TagName }</span>
<span class="text-xs text-muted-foreground ml-auto">{ overviewPeriodLabel(b.Period) }</span>
</div>
<div class="flex justify-between text-xs text-muted-foreground">