mirror of
https://github.com/we-promise/sure.git
synced 2026-05-28 06:54:56 +00:00
* feat(design-system): DS::Disclosure :card variant + migrate 14 provider items Resolves part of #1715 §6. The provider-item view templates (binance, brex, coinbase, coinstats, enable_banking, ibkr, indexa_capital, kraken, lunchflow, mercury, plaid, simplefin, snaptrade, sophtron — 14 in total) all hand-rolled the same `<details open class="group bg-container p-4 shadow-border-xs rounded-xl">` shell with a custom summary inside and content below. Extend `DS::Disclosure` with a `:card` variant that bakes the card chrome onto the `<details>` element itself; the summary becomes slot-driven via the existing `summary_content` slot. Provider items keep their custom summary content (logos, brand colors, status copy) unchanged — they just hand it to the slot instead of writing it between `<summary>` tags. API: DS::Disclosure.new(variant: :card, open: true) do |d| d.with_summary_content do <div class="flex items-center gap-2"> chevron + custom summary markup </div> end body content end While here: - Drop the no-op `group-open:transform` from the default chevron (Tailwind v4 applies `rotate-90` directly). - Add `motion-safe:transition-transform motion-safe:duration-150` to chevron rotation for reduced-motion respect (matches the pattern landing in #1841). - Extract `summary_classes` / `details_classes` helpers so the default and card surfaces stay readable side-by-side. Note: this PR touches `DS::Disclosure` and will textually conflict with #1841 (focus-ring + reduced-motion polish). Both changes are compatible — when #1841 merges first, the resolution is just preserving both edits (the focus-ring classes are already merged into `summary_classes` here). * feat(design-system): migrate 3 provider panels to DS::Disclosure :card variant Resolves the panel slice of #1715 §6. Continuation of the DS::Disclosure :card variant work — same migration pattern, applied to the 3 provider-PANEL templates that share the card shape with the provider-item templates landing on the parent branch. Migrated `<details class="group bg-container p-4 shadow-border-xs rounded-xl">` → `DS::Disclosure.new(variant: :card)` in: - `app/views/settings/providers/_kraken_panel.html.erb` — 1 details in the items-each loop. - `app/views/settings/providers/_mercury_panel.html.erb` — 1 details in the items-each loop. - `app/views/settings/providers/_brex_panel.html.erb` — 2 details: one in the items-each loop, one standalone "add connection" panel that opened by default when no active items existed. The conditional `<%= "open" unless active_items.any? %>` becomes `open: active_items.none?` on the `:card` disclosure. Panels do NOT show a chevron in their summary (different UX from the per-item rows in #1855), so the migration preserves that — no chevron inserted. NOT migrated (intentionally — different shapes): - `_ibkr_panel.html.erb` — `<details class="group bg-surface-inset rounded-xl p-4">`. Uses bg-surface-inset, not bg-container — needs a `:card-inset` variant we haven't built. Deferred. - `_indexa_capital_panel.html.erb` — `<details class="group">` with no card chrome. Inline expander; doesn't fit either disclosure variant. - `_snaptrade_panel.html.erb` — same inline pattern as indexa_capital. * fix(review): use ring-alpha-black-300 focus token in DS::Disclosure CodeRabbit P2: switch the focus-visible outline from raw gray-900/white palette values to the alpha-black-300 ring token, matching the established focus pattern on settings/provider_card.html.erb. This keeps theme behavior centralized in the design system tokens instead of branching on theme-dark: in the component. Applies to both :default and :card summary variants. * fix(review): stretch DS::Disclosure summary_content to full width Codex P2 follow-up on the disclosure-migration stack: \`<summary>\` is \`display: list-item\`, so a flex inner div inside the slot shrink-wraps to content width — any \`justify-between\` the caller adds has nothing to distribute, and the right-side admin actions collapse toward the title across every provider-item partial migrated to \`DS::Disclosure variant: :card\` in #1855 (and the panels in #1856 / #1857 / #1858 that inherit this component). Wrap the slot in \`<div class=\"w-full\">\` so caller-supplied flex rows stretch across the card. \`:default\` variant is unchanged (it never uses \`summary_content\`). * fix(review): stretch :card summary flex row to full width Codex P2 follow-up on #1856: the migrated kraken / mercury / brex panel summary rows wrap their content in \`<div class=\"flex items-center justify-between gap-X\">\`, but a flex container inside \`<summary>\` (\`display: list-item\`) shrink-wraps to content size, so \`justify-between\` had nothing to distribute and the right-side admin actions collapsed toward the title. Add \`w-full\` so the flex row stretches across the card. The deeper component-level fix lands in #1855 (wraps \`summary_content\` in a \`w-full\` block); this commit makes #1856 self-contained against the merge order.
126 lines
6.2 KiB
Plaintext
126 lines
6.2 KiB
Plaintext
<div id="mercury-providers-panel" class="space-y-4">
|
|
<% active_items = local_assigns[:mercury_items] || @mercury_items || Current.family.mercury_items.active.ordered %>
|
|
<% credentialed_items = active_items.select(&:credentials_configured?) %>
|
|
|
|
<%= render "settings/providers/setup_steps",
|
|
steps: [
|
|
t("mercury_items.provider_panel.instructions.sign_in_html", link: link_to("Mercury", "https://mercury.com", target: "_blank", rel: "noopener noreferrer", class: "text-primary font-medium underline")).html_safe,
|
|
t("mercury_items.provider_panel.instructions.open_tokens"),
|
|
t("mercury_items.provider_panel.instructions.create_token"),
|
|
t("mercury_items.provider_panel.instructions.whitelist_ip_html").html_safe,
|
|
t("mercury_items.provider_panel.instructions.copy_token_html").html_safe
|
|
] %>
|
|
|
|
<% error_msg = local_assigns[:error_message] || @error_message %>
|
|
<% if error_msg.present? %>
|
|
<%= render DS::Alert.new(message: error_msg, variant: :error) %>
|
|
<% end %>
|
|
|
|
<% if active_items.any? %>
|
|
<div class="space-y-3">
|
|
<% active_items.each do |item| %>
|
|
<%= render DS::Disclosure.new(variant: :card) do |disclosure| %>
|
|
<% disclosure.with_summary_content do %>
|
|
<div class="flex items-center justify-between gap-2 w-full">
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex items-center justify-center h-8 w-8 bg-blue-600/10 rounded-full">
|
|
<p class="text-blue-600 text-xs font-medium"><%= item.name.to_s.first.to_s.upcase %></p>
|
|
</div>
|
|
<div>
|
|
<p class="font-medium text-primary"><%= item.name %></p>
|
|
<p class="text-xs text-secondary"><%= item.sync_status_summary %></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex items-center gap-2">
|
|
<%= button_to sync_mercury_item_path(item),
|
|
method: :post,
|
|
class: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-secondary hover:text-primary border border-secondary rounded-lg hover:border-primary",
|
|
disabled: item.syncing? do %>
|
|
<%= icon "refresh-cw", size: "sm" %>
|
|
<%= t("mercury_items.provider_panel.sync") %>
|
|
<% end %>
|
|
<%= button_to mercury_item_path(item),
|
|
method: :delete,
|
|
class: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10 rounded-lg",
|
|
data: { turbo_confirm: t("mercury_items.provider_panel.disconnect_confirm", name: item.name) } do %>
|
|
<%= icon "trash-2", size: "sm" %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<%= styled_form_with model: item,
|
|
url: mercury_item_path(item),
|
|
scope: :mercury_item,
|
|
method: :patch,
|
|
data: { turbo: true },
|
|
class: "space-y-3" do |form| %>
|
|
<%= form.text_field :name,
|
|
label: t("mercury_items.provider_panel.connection_name_label"),
|
|
placeholder: t("mercury_items.provider_panel.connection_name_placeholder") %>
|
|
|
|
<%= form.text_field :token,
|
|
label: t("mercury_items.provider_panel.token_label"),
|
|
placeholder: t("mercury_items.provider_panel.keep_token_placeholder"),
|
|
type: :password,
|
|
value: nil %>
|
|
|
|
<%= form.text_field :base_url,
|
|
label: t("mercury_items.provider_panel.base_url_label"),
|
|
placeholder: t("mercury_items.provider_panel.base_url_placeholder"),
|
|
value: item.base_url %>
|
|
|
|
<div class="flex flex-wrap justify-end gap-2">
|
|
<%= render DS::Link.new(
|
|
text: t("mercury_items.provider_panel.setup_accounts"),
|
|
icon: "settings",
|
|
variant: "secondary",
|
|
href: setup_accounts_mercury_item_path(item),
|
|
frame: :modal
|
|
) %>
|
|
<%= form.submit t("mercury_items.provider_panel.update_connection") %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% mercury_item = Current.family.mercury_items.build(name: t("mercury_items.provider_panel.default_connection_name")) %>
|
|
<% if active_items.any? %>
|
|
<h3 class="flex items-center gap-2 text-sm font-medium text-primary mt-4">
|
|
<%= icon "plus", size: "sm" %>
|
|
<%= t("mercury_items.provider_panel.add_connection") %>
|
|
</h3>
|
|
<% end %>
|
|
<%= styled_form_with model: mercury_item,
|
|
url: mercury_items_path,
|
|
scope: :mercury_item,
|
|
method: :post,
|
|
data: { turbo: true },
|
|
class: "space-y-3" do |form| %>
|
|
<%= form.text_field :name,
|
|
label: t("mercury_items.provider_panel.connection_name_label"),
|
|
placeholder: t("mercury_items.provider_panel.connection_name_placeholder") %>
|
|
|
|
<%= form.text_field :token,
|
|
label: t("mercury_items.provider_panel.token_label"),
|
|
placeholder: t("mercury_items.provider_panel.token_placeholder"),
|
|
type: :password,
|
|
value: nil %>
|
|
|
|
<%= form.text_field :base_url,
|
|
label: t("mercury_items.provider_panel.base_url_label"),
|
|
placeholder: t("mercury_items.provider_panel.base_url_placeholder") %>
|
|
<p class="text-xs text-secondary px-1 -mt-1"><%= t("mercury_items.provider_panel.sandbox_note_html").html_safe %></p>
|
|
|
|
<div class="flex justify-end">
|
|
<%= form.submit t("mercury_items.provider_panel.add_connection") %>
|
|
</div>
|
|
<% end %>
|
|
|
|
</div>
|