From 6abceb07ffb6b0c237de04af464d275293b32039 Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Sat, 9 May 2026 13:48:09 +0200 Subject: [PATCH] fix(settings/providers): drop colour palette + filter polish + drawer warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round of design-feedback fixes. Provider chips - Drop the per-provider raw Tailwind palette (bg-blue-600 etc.) from Provider::Metadata. All cards + drawer logo lock-up now use bg-surface-inset + text-primary, matching the design's §04 "drop colour entirely" recommendation. Solves the long-standing §01 BLOCKER without externalising brand assets. Re-introducing logos later just means an optional logo_svg: field on metadata. - ProviderCard component drops the `logo_bg:` parameter; the chip is now styled in the template. Filter / search - "Available · N" count and the empty-filter state now update client-side as the chip filter and free-text search narrow the grid (new `count` Stimulus target + dedicated update path). - Empty-filter state now offers a Clear filters button that resets both the search input and the active chip in one click. - Search placeholder drops the drifting "Search 9 providers" count for plain "Search providers" — the section heading carries the number. - Chip labels normalised to plural where natural: "Banks · Crypto · Investments" (Crypto stays as the mass noun). Drawer copy / treatment - "IP Whitelisting Required" → "IP whitelisting required" (DS sentence-case). - Binance "do NOT enable withdrawal permissions" lifted out of inline red-text into a proper bg-warning-50 border-warning-200 alert block with an alert-triangle icon. Matches the api_keys / hosting alert pattern. - SnapTrade free-tier inline alert-triangle now uses `size: "sm"` so the icon stops rendering at 20px next to 14px body text. Spacing - Group-heading margin top bumped 5 → 6 (20→24px) so the eyebrow has more breathing room above the search bar. --- .../settings/provider_card.html.erb | 4 +- app/components/settings/provider_card.rb | 5 +- .../providers_filter_controller.js | 16 ++- app/models/provider/metadata.rb | 101 +++--------------- .../providers/_binance_panel.html.erb | 6 +- .../providers/_drawer_header.html.erb | 6 +- .../providers/_group_heading.html.erb | 2 +- .../providers/_search_filters.html.erb | 3 +- .../providers/_snaptrade_panel.html.erb | 2 +- app/views/settings/providers/show.html.erb | 24 +++-- config/locales/views/settings/en.yml | 9 +- 11 files changed, 62 insertions(+), 116 deletions(-) diff --git a/app/components/settings/provider_card.html.erb b/app/components/settings/provider_card.html.erb index c30204d82..619bf0eb5 100644 --- a/app/components/settings/provider_card.html.erb +++ b/app/components/settings/provider_card.html.erb @@ -2,8 +2,8 @@ class: "bg-container shadow-border-xs rounded-xl p-4 flex flex-col gap-2.5 text-primary hover:bg-container-hover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-alpha-black-100", data: { turbo_frame: "drawer", turbo_prefetch: "false" }.merge(filter_data) do %>
-
- <%= logo_text %> +
+ <%= logo_text %>
diff --git a/app/components/settings/provider_card.rb b/app/components/settings/provider_card.rb index c57657a2e..e96a69336 100644 --- a/app/components/settings/provider_card.rb +++ b/app/components/settings/provider_card.rb @@ -10,7 +10,7 @@ class Settings::ProviderCard < ApplicationComponent end def initialize(provider_key:, name:, tagline: nil, region: nil, kind: nil, tier: nil, - maturity: :stable, logo_bg: "bg-gray-500", logo_text: nil) + maturity: :stable, logo_text: nil) @provider_key = provider_key @name = name @tagline = tagline @@ -18,11 +18,10 @@ class Settings::ProviderCard < ApplicationComponent @kind = kind @tier = tier @maturity = maturity.to_sym - @logo_bg = logo_bg @logo_text = logo_text || name.first(2).upcase end - attr_reader :name, :tagline, :logo_bg, :logo_text + attr_reader :name, :tagline, :logo_text def maturity_label self.class.maturity_label(@maturity) diff --git a/app/javascript/controllers/providers_filter_controller.js b/app/javascript/controllers/providers_filter_controller.js index e7134de8c..54004b2f6 100644 --- a/app/javascript/controllers/providers_filter_controller.js +++ b/app/javascript/controllers/providers_filter_controller.js @@ -2,8 +2,10 @@ import { Controller } from "@hotwired/stimulus"; // Connects to data-controller="providers-filter" // Filters provider cards by free-text query and a chip-selected kind. +// Updates the visible-count target on the section heading and toggles +// an empty-state target when no card matches. export default class extends Controller { - static targets = ["input", "chip", "card", "empty"]; + static targets = ["input", "chip", "card", "empty", "count"]; static values = { kind: { type: String, default: "all" } }; connect() { @@ -29,6 +31,10 @@ export default class extends Controller { if (visible) visibleCount++; }); + if (this.hasCountTarget) { + this.countTarget.textContent = visibleCount; + } + if (this.hasEmptyTarget) { this.emptyTarget.classList.toggle("hidden", visibleCount > 0); } @@ -40,6 +46,14 @@ export default class extends Controller { this.filter(); } + clear() { + if (this.hasInputTarget) this.inputTarget.value = ""; + this.kindValue = "all"; + this.syncChipState(); + this.filter(); + if (this.hasInputTarget) this.inputTarget.focus(); + } + syncChipState() { if (!this.hasChipTarget) return; this.chipTargets.forEach((chip) => { diff --git a/app/models/provider/metadata.rb b/app/models/provider/metadata.rb index 702e0f4ee..dfdb48be7 100644 --- a/app/models/provider/metadata.rb +++ b/app/models/provider/metadata.rb @@ -1,97 +1,22 @@ class Provider module Metadata REGISTRY = { - simplefin: { - region: "US", - kind: "Bank", - maturity: :stable, - logo_bg: "bg-blue-600", - logo_text: "SF" - }, - lunchflow: { - region: "US", - kind: "Bank", - maturity: :stable, - logo_bg: "bg-orange-500", - logo_text: "LF" - }, - enable_banking: { - region: "EU", - kind: "Bank", - maturity: :beta, - logo_bg: "bg-purple-600", - logo_text: "EB" - }, - coinstats: { - region: "Global", - kind: "Crypto", - maturity: :beta, - logo_bg: "bg-yellow-500", - logo_text: "CS" - }, - mercury: { - region: "US", - kind: "Bank", - maturity: :beta, - logo_bg: "bg-cyan-600", - logo_text: "ME" - }, - coinbase: { - region: "Global", - kind: "Crypto", - maturity: :beta, - logo_bg: "bg-blue-500", - logo_text: "CB" - }, - binance: { - region: "Global", - kind: "Crypto", - maturity: :beta, - logo_bg: "bg-yellow-400", - logo_text: "BI" - }, - snaptrade: { - region: "US / CA", - kind: "Investment", - maturity: :beta, - logo_bg: "bg-green-600", - logo_text: "ST" - }, - indexa_capital: { - region: "ES", - kind: "Investment", - maturity: :alpha, - logo_bg: "bg-red-600", - logo_text: "IC" - }, - sophtron: { - region: "US", - kind: "Bank", - maturity: :alpha, - logo_bg: "bg-teal-600", - logo_text: "SO" - }, - plaid: { - region: "US", - kind: "Bank", - tier: "Paid", - maturity: :stable, - logo_bg: "bg-indigo-600", - logo_text: "PL" - }, - plaid_eu: { - name: "Plaid EU", - region: "EU", - kind: "Bank", - tier: "Paid", - maturity: :stable, - logo_bg: "bg-indigo-600", - logo_text: "PL" - } + simplefin: { region: "US", kind: "Bank", maturity: :stable, logo_text: "SF" }, + lunchflow: { region: "US", kind: "Bank", maturity: :stable, logo_text: "LF" }, + enable_banking: { region: "EU", kind: "Bank", maturity: :beta, logo_text: "EB" }, + coinstats: { region: "Global", kind: "Crypto", maturity: :beta, logo_text: "CS" }, + mercury: { region: "US", kind: "Bank", maturity: :beta, logo_text: "ME" }, + coinbase: { region: "Global", kind: "Crypto", maturity: :beta, logo_text: "CB" }, + binance: { region: "Global", kind: "Crypto", maturity: :beta, logo_text: "BI" }, + snaptrade: { region: "US / CA", kind: "Investment", maturity: :beta, logo_text: "ST" }, + indexa_capital: { region: "ES", kind: "Investment", maturity: :alpha, logo_text: "IC" }, + sophtron: { region: "US", kind: "Bank", maturity: :alpha, logo_text: "SO" }, + plaid: { region: "US", kind: "Bank", tier: "Paid", maturity: :stable, logo_text: "PL" }, + plaid_eu: { name: "Plaid EU", region: "EU", kind: "Bank", tier: "Paid", maturity: :stable, logo_text: "PL" } }.freeze def self.for(provider_key) - REGISTRY[provider_key.to_sym] || { logo_text: provider_key.to_s.first(2).upcase, logo_bg: "bg-gray-500" } + REGISTRY[provider_key.to_sym] || { logo_text: provider_key.to_s.first(2).upcase } end end end diff --git a/app/views/settings/providers/_binance_panel.html.erb b/app/views/settings/providers/_binance_panel.html.erb index 2ad0158e2..f555ff912 100644 --- a/app/views/settings/providers/_binance_panel.html.erb +++ b/app/views/settings/providers/_binance_panel.html.erb @@ -8,7 +8,11 @@
  • <%= t("settings.providers.binance_panel.step2") %>
  • <%= t("settings.providers.binance_panel.step3") %>
  • -

    <%= t("settings.providers.binance_panel.no_withdraw_warning") %>

    +
    + +
    + <%= icon "alert-triangle", size: "sm", class: "!w-3.5 !h-3.5 text-warning-600 shrink-0 mt-0.5" %> +

    <%= t("settings.providers.binance_panel.no_withdraw_warning") %>

    diff --git a/app/views/settings/providers/_drawer_header.html.erb b/app/views/settings/providers/_drawer_header.html.erb index df439dafd..9cb044843 100644 --- a/app/views/settings/providers/_drawer_header.html.erb +++ b/app/views/settings/providers/_drawer_header.html.erb @@ -3,9 +3,9 @@ <% maturity_label = meta ? Settings::ProviderCard.maturity_label(meta[:maturity]) : nil %>
    - <% if meta && meta[:logo_bg].present? %> - - <%= meta[:logo_text] %> + <% if meta && meta[:logo_text].present? %> + + <%= meta[:logo_text] %> <% end %>

    <%= title %>

    diff --git a/app/views/settings/providers/_group_heading.html.erb b/app/views/settings/providers/_group_heading.html.erb index 970be0443..e0a831f49 100644 --- a/app/views/settings/providers/_group_heading.html.erb +++ b/app/views/settings/providers/_group_heading.html.erb @@ -1,5 +1,5 @@ <%# locals: (title:, count: nil, description: nil, anchor: nil) %> -<%= tag.div id: anchor.presence, class: "flex items-baseline justify-between gap-3 mt-5 mb-1.5 px-1" do %> +<%= tag.div id: anchor.presence, class: "flex items-baseline justify-between gap-3 mt-6 mb-1.5 px-1" do %>

    <%= title %> <% if count %> diff --git a/app/views/settings/providers/_search_filters.html.erb b/app/views/settings/providers/_search_filters.html.erb index 4d79586cb..f4c295faf 100644 --- a/app/views/settings/providers/_search_filters.html.erb +++ b/app/views/settings/providers/_search_filters.html.erb @@ -1,4 +1,3 @@ -<%# locals: (count:) %>
    " - placeholder="<%= t("settings.providers.search_filters.placeholder", count: count) %>" + placeholder="<%= t("settings.providers.search_filters.placeholder") %>" class="block w-full border border-secondary rounded-md py-2.5 pl-10 pr-3 bg-container focus:ring-gray-500 sm:text-sm">
    <%= icon "search", class: "text-secondary" %> diff --git a/app/views/settings/providers/_snaptrade_panel.html.erb b/app/views/settings/providers/_snaptrade_panel.html.erb index 8475eee91..fdacf3424 100644 --- a/app/views/settings/providers/_snaptrade_panel.html.erb +++ b/app/views/settings/providers/_snaptrade_panel.html.erb @@ -10,7 +10,7 @@
  • <%= t("providers.snaptrade.step_4") %>
  • -

    <%= icon("alert-triangle", class: "inline-block w-4 h-4 mr-1") %><%= t("providers.snaptrade.free_tier_warning") %>

    +

    <%= icon("alert-triangle", size: "sm", class: "inline-block mr-1") %><%= t("providers.snaptrade.free_tier_warning") %>

    <% error_msg = local_assigns[:error_message] || @error_message %> diff --git a/app/views/settings/providers/show.html.erb b/app/views/settings/providers/show.html.erb index 42ccdae66..11d085887 100644 --- a/app/views/settings/providers/show.html.erb +++ b/app/views/settings/providers/show.html.erb @@ -46,16 +46,23 @@ <% if @available.any? %>
    - <%= render "settings/providers/search_filters", count: @available.size %> + <%= render "settings/providers/search_filters" %> - <%= render "settings/providers/group_heading", - title: t("settings.providers.groups.available"), - count: @available.size, - anchor: "available" %> +
    +

    + <%= t("settings.providers.groups.available") %> + + · <%= @available.size %> + +

    +
    - +
    <% @available.each do |entry| %> @@ -68,7 +75,6 @@ kind: meta[:kind], tier: meta[:tier], maturity: meta[:maturity] || :stable, - logo_bg: meta[:logo_bg], logo_text: meta[:logo_text] ) %> <% end %> diff --git a/config/locales/views/settings/en.yml b/config/locales/views/settings/en.yml index b6b26fb4d..1d424ef3f 100644 --- a/config/locales/views/settings/en.yml +++ b/config/locales/views/settings/en.yml @@ -234,15 +234,14 @@ en: plaid_eu: Connect European financial institutions via Plaid (PSD2 / Open Banking). search_filters: aria_label: Search providers - placeholder: - one: "Search %{count} provider" - other: "Search %{count} providers" + placeholder: Search providers chips: all: All bank: Banks crypto: Crypto - investment: Investment + investment: Investments empty_filter: No providers match your filter. + clear_filter: Clear filters encryption_error: title: Encryption Configuration Required message: Active Record encryption keys are not configured. Please ensure the encryption credentials (active_record_encryption.primary_key, active_record_encryption.deterministic_key, and active_record_encryption.key_derivation_salt) are properly set up in your Rails credentials or environment variables before using sync providers. @@ -265,7 +264,7 @@ en: step2: "Create a new API key with Enable Reading permission only" step3: "Paste your API Key and Secret below" no_withdraw_warning: "Warning: do NOT enable withdrawal permissions" - ip_hint_title: "IP Whitelisting Required" + ip_hint_title: "IP whitelisting required" ip_hint_body: "Add the app server's egress IP to the Binance API Key whitelist:" ip_hint_contact_admin: "Contact your administrator to obtain the app server's egress IP address." api_key_label: API Key