diff --git a/app/components/DS/pill.rb b/app/components/DS/pill.rb index 6e6aae924..899c97345 100644 --- a/app/components/DS/pill.rb +++ b/app/components/DS/pill.rb @@ -104,24 +104,26 @@ class DS::Pill < DesignSystemComponent def container_classes base = [ "inline-flex items-center align-middle font-medium whitespace-nowrap shrink-0", - "border rounded-md", - "leading-none" + "border leading-none" ] if marker - # Marker mode (Beta / Canary / NEW): uppercase, sub-12px text, - # wider tracking. text-[10/11px] stays as arbitrary values — the - # pill is intentionally sub-12px (Sure's smallest scale token is - # text-xs / 12px) so it reads as a marker, not a label. Padding / - # gap / tracking snap to Tailwind's scale to satisfy the - # design-system "no arbitrary values" rule. - base << "uppercase" + # Marker mode (Beta / Canary / NEW): rounded-md (slight chip + # shape), uppercase, sub-12px text, wider tracking. + # text-[10/11px] stays as arbitrary values — the pill is + # intentionally sub-12px (Sure's smallest scale token is text-xs + # / 12px) so it reads as a marker, not a label. Padding / gap / + # tracking snap to Tailwind's scale to satisfy the design-system + # "no arbitrary values" rule. + base << "rounded-md uppercase" base << (size == :md ? "px-2 py-0.5 text-[11px] tracking-wide gap-1" : "px-1.5 py-0.5 text-[10px] tracking-wider gap-1") else # Badge mode (Pending / Active / Past due / category tag): - # normal case, snaps to the design-system text scale - # (`text-xs` / `text-sm`). Padding bumps slightly so the badge - # reads as a status chip rather than a sub-12px marker. + # rounded-full pill shape (matches the existing convention used + # by `settings/providers/_status_pill`, `_maturity_badge`, and + # the inline transaction badges). Normal case, snaps to the + # design-system text scale (`text-xs` / `text-sm`). + base << "rounded-full" base << (size == :md ? "px-2 py-0.5 text-sm gap-1.5" : "px-1.5 py-0.5 text-xs gap-1") end class_names(*base) diff --git a/app/views/transactions/_header.html.erb b/app/views/transactions/_header.html.erb index a5ca70b63..26fcacd94 100644 --- a/app/views/transactions/_header.html.erb +++ b/app/views/transactions/_header.html.erb @@ -22,10 +22,13 @@ <%= entry.date ? I18n.l(entry.date, format: :long) : "—" %> <% if entry.transaction.pending? %> - "> - <%= icon "clock", size: "sm", color: "current" %> - <%= t("transactions.transaction.pending") %> - + <%= render DS::Pill.new( + label: t("transactions.transaction.pending"), + tone: :neutral, + marker: false, + icon: "clock", + title: t("transactions.transaction.pending_tooltip") + ) %> <% end %> diff --git a/app/views/transactions/_split_parent_row.html.erb b/app/views/transactions/_split_parent_row.html.erb index 99bf6a086..f2e68eca6 100644 --- a/app/views/transactions/_split_parent_row.html.erb +++ b/app/views/transactions/_split_parent_row.html.erb @@ -36,10 +36,12 @@
- - <%= icon "split", size: "sm", color: "current" %> - <%= t("transactions.split_parent_row.split_label") %> - + <%= render DS::Pill.new( + label: t("transactions.split_parent_row.split_label"), + tone: :neutral, + marker: false, + icon: "split" + ) %>
diff --git a/app/views/transactions/_transaction.html.erb b/app/views/transactions/_transaction.html.erb index 659591bff..8bccd8b4e 100644 --- a/app/views/transactions/_transaction.html.erb +++ b/app/views/transactions/_transaction.html.erb @@ -98,33 +98,45 @@ <%# Pending indicator %> <% if transaction.pending? %> - "> - <%= icon "clock", size: "sm", color: "current" %> - <%= t("transactions.transaction.pending") %> - + <%= render DS::Pill.new( + label: t("transactions.transaction.pending"), + tone: :neutral, + marker: false, + icon: "clock", + title: t("transactions.transaction.pending_tooltip") + ) %> <% end %> <%# Potential duplicate indicator - different styling for low vs medium confidence %> <% if transaction.has_potential_duplicate? %> <% if transaction.low_confidence_duplicate? %> - "> - <%= icon "help-circle", size: "sm", color: "current" %> - <%= t("transactions.transaction.review_recommended") %> - + <%= render DS::Pill.new( + label: t("transactions.transaction.review_recommended"), + tone: :neutral, + marker: false, + icon: "help-circle", + title: t("transactions.transaction.review_recommended_tooltip") + ) %> <% else %> - "> - <%= icon "alert-triangle", size: "sm", color: "current" %> - <%= t("transactions.transaction.possible_duplicate") %> - + <%= render DS::Pill.new( + label: t("transactions.transaction.possible_duplicate"), + tone: :warning, + marker: false, + icon: "alert-triangle", + title: t("transactions.transaction.potential_duplicate_tooltip") + ) %> <% end %> <% end %> <%# Split indicator %> <% if @split_parent_entry_ids ? @split_parent_entry_ids.include?(entry.id) : entry.split_parent? %> - "> - <%= icon "split", size: "sm", color: "current" %> - <%= t("transactions.transaction.split") %> - + <%= render DS::Pill.new( + label: t("transactions.transaction.split"), + tone: :neutral, + marker: false, + icon: "split", + title: t("transactions.transaction.split_tooltip") + ) %> <% end %> <% if entry.split_child? && !in_split_group %> "> diff --git a/test/components/DS/pill_test.rb b/test/components/DS/pill_test.rb index f108593b4..aab1cc9ad 100644 --- a/test/components/DS/pill_test.rb +++ b/test/components/DS/pill_test.rb @@ -1,16 +1,19 @@ require "test_helper" class DS::PillTest < ViewComponent::TestCase - test "marker mode (default) renders uppercase sub-12px chrome" do + test "marker mode (default) renders uppercase sub-12px chrome with rounded-md" do render_inline(DS::Pill.new(label: "Beta", tone: :violet)) pill = page.find("span", text: "Beta") assert_includes pill[:class], "uppercase" # Marker keeps sub-12px text via arbitrary value (intentional — see component docs). assert_match(/text-\[1[01]px\]/, pill[:class]) + # Marker uses rounded-md (chip shape). + assert_includes pill[:class], "rounded-md" + refute_includes pill[:class], "rounded-full" end - test "marker: false renders normal-case DS-scale chrome" do + test "marker: false renders normal-case DS-scale chrome with rounded-full" do render_inline(DS::Pill.new(label: "Active", tone: :success, marker: false)) pill = page.find("span", text: "Active") @@ -18,6 +21,9 @@ class DS::PillTest < ViewComponent::TestCase # Badge mode snaps to text-xs / text-sm — no sub-12px arbitrary values. assert_match(/text-(xs|sm)/, pill[:class]) refute_match(/text-\[1[01]px\]/, pill[:class]) + # Badge uses rounded-full to match the existing _status_pill / _maturity_badge convention. + assert_includes pill[:class], "rounded-full" + refute_includes pill[:class], "rounded-md" end test "semantic tone aliases resolve to visual palette tones" do @@ -51,9 +57,9 @@ class DS::PillTest < ViewComponent::TestCase # Lucide icon helper renders the inline SVG; verifying we see at least one # is enough — the icon helper is covered by its own tests. assert_selector "svg" - # And the dot is suppressed when an icon takes its place. `refute_selector - # ..., count: N` only fails when there are exactly N matches, so use - # `assert_no_selector` to strictly assert zero dots. - assert_no_selector "span.rounded-full[style*='background-color']" + # And the dot is suppressed when an icon takes its place. The dot is an + # `inline-block` span (parent pill is `inline-flex`), so target it by + # `inline-block.rounded-full` to avoid matching the parent pill. + assert_no_selector "span.inline-block.rounded-full" end end