diff --git a/internal/templates/components/pages/counterparties.templ b/internal/templates/components/pages/counterparties.templ index b17055b1..49545808 100644 --- a/internal/templates/components/pages/counterparties.templ +++ b/internal/templates/components/pages/counterparties.templ @@ -89,18 +89,22 @@ templ counterpartiesListRow(c CounterpartyRow) { // CounterpartyDetail renders /counterparties/{short_id} under the // rules-as-substrate model: a counterparty IS the rules that define it. The page -// pairs the LINKED CHARGES (what's bound to it) with the GOVERNING RULES (the -// assign_counterparty rules that put them there), and adds a manual ENRICHMENT -// form (name, category, mcc, website, logo). Enrichment is a plain POST → -// UpdateCounterparty; no auto-fetch. +// reads as a calm brand profile — the header carries the identity (logo, name, +// category chip, website · MCC · charge-count facts), and the body pairs the +// LINKED CHARGES (what's bound to it) with the GOVERNING RULES (the +// assign_counterparty rules that put them there). Enrichment (name, category, +// mcc, website, logo) edits in a right-side Drawer opened from the header — the +// detail-page sibling of the series edit drawer (design-system principle #5). templ CounterpartyDetail(p CounterpartyDetailProps) { -
+
@components.EntityHeader(components.EntityHeaderProps{ Title: p.Counterparty.Name, TitlePrivateKind: "merchant", IconComponent: counterpartyHeaderIcon(p.Counterparty), IconTone: components.IconToneDefault, + Badges: counterpartyDetailBadges(p), Meta: counterpartyDetailMeta(p), + Action: counterpartyEditBtn(), })
@@ -129,47 +133,82 @@ templ CounterpartyDetail(p CounterpartyDetailProps) { })
- -
- @entityPanelHeader("sparkles", "Enrichment", "Name, category, and brand details", nil) -
- - @components.SettingsSection(components.SettingsSectionProps{ - Icon: "store", - Title: "Details", - }) { - @components.SettingsRow(components.SettingsRowProps{Label: "Name", Caption: "Display label for this counterparty"}) { - - } - @components.SettingsRow(components.SettingsRowProps{Label: "Category", Caption: "Default category for its charges"}) { - - } - @components.SettingsRow(components.SettingsRowProps{Label: "MCC", Caption: "Merchant category code (4 digits)"}) { - - } - @components.SettingsRow(components.SettingsRowProps{Label: "Website", Caption: "Its domain auto-fetches a brand logo via logo.dev when counterparty logos are enabled and a logo.dev token is set in Settings", Stack: true}) { - - } - @components.SettingsRow(components.SettingsRowProps{Label: "Logo URL", Caption: "Overrides the auto-fetched logo. Hotlinked on counterparty rows.", Stack: true}) { - - } - } -
- -
-
-
+ @counterpartyEditDrawer(p)
} +// counterpartyDetailBadges is the EntityHeader badge row — a quiet category chip +// when the counterparty has a default category set. Neutral metadata, so a ghost +// badge (vivid tones are reserved for status per the design system). +templ counterpartyDetailBadges(p CounterpartyDetailProps) { + if cat := counterpartyCategoryLabel(p); cat != "" { + { cat } + } +} + +// counterpartyEditBtn is the EntityHeader trailing action — a single Edit +// affordance that opens the enrichment drawer (matches the series detail). +templ counterpartyEditBtn() { + +} + +// counterpartyEditDrawer is the right-side slide-over for enrichment — name, +// category, mcc, website, logo — committed with one explicit Save. Plain POST → +// UpdateCounterparty (no Alpine factory); the Drawer shell handles open/close via +// $store.drawers. Single-column stacked fields (the drawer is narrow). +templ counterpartyEditDrawer(p CounterpartyDetailProps) { + @components.Drawer(components.DrawerProps{ID: "counterparty-edit", Title: "Edit counterparty"}) { +
+ + @components.DrawerHeader(components.DrawerHeaderProps{Icon: "store", Title: "Edit counterparty", Subtitle: "Name, category, and brand details"}) +
+
+ + +

Display label for this counterparty.

+
+
+ + +

Default category for its charges.

+
+
+ + +

Merchant category code (4 digits).

+
+
+ + +

Its domain auto-fetches a brand logo via logo.dev when counterparty logos are enabled and a token is set in Settings.

+
+
+ + +

Overrides the auto-fetched logo. Hotlinked on counterparty rows.

+
+
+ @components.DrawerFooter() { + + + } +
+ } +} + // CounterpartyForm renders /counterparties/new — a from-scratch create form. A // counterparty needs only a name; enrich it and point rules at it afterwards. // Plain POST → CreateCounterpartyPageHandler creates the counterparty and @@ -180,30 +219,33 @@ templ CounterpartyForm(p CounterpartyFormProps) { Subtitle: "Name a counterparty, then enrich it and author rules that assign charges to it. It starts empty.", SubtitleHideOnMobile: true, }) -
- - if p.Error != "" { -