Merge origin/main into feat/goals-v2-architecture

Pulls in #1857 (DS::Disclosure :card_inset), #1858 (:inline variant),
#1902 (DS::Pill marker:false + semantic tones + :red palette), #1903
(settings/debugs token fix), plus #1878 (entry.date guard) and other
minor fixes that landed.

Resolves one conflict in app/components/DS/pill.rb: takes main's new
extended API (marker: flag, SEMANTIC_TONE_ALIASES, :red tone, updated
docstring) and preserves the goals-branch color-mix(...30% black)
text treatment that was added for light-mode contrast. Applies the
same color-mix to the new :red tone for consistency.
This commit is contained in:
Guillem Arias
2026-05-22 08:53:10 +02:00
18 changed files with 280 additions and 93 deletions

View File

@@ -55,7 +55,7 @@
<% if enable_banking_item.requires_update? %>
<%= button_to reauthorize_enable_banking_item_path(enable_banking_item),
method: :post,
class: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg text-white bg-warning hover:opacity-90 transition-colors",
class: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg text-inverse bg-warning hover:opacity-90 transition-colors",
data: { turbo: false } do %>
<%= icon "refresh-cw", size: "sm" %>
<%= t(".update") %>

View File

@@ -9,7 +9,7 @@
<div class="flex items-center gap-2">
<%= icon "chevron-right", class: "group-open:rotate-90 motion-safe:transition-transform motion-safe:duration-150" %>
<div class="flex items-center justify-center h-8 w-8 bg-gray-tint-10 rounded-full">
<div class="flex items-center justify-center h-8 w-8 bg-container-inset rounded-full">
<div class="flex items-center justify-center">
<%= tag.p indexa_capital_item.name.first.upcase, class: "text-primary text-xs font-medium" %>
</div>

View File

@@ -52,7 +52,7 @@
<div class="flex-1 text-sm">
<div class="font-medium text-primary"><%= entry.name %></div>
<div class="text-xs text-secondary">
<%= I18n.l(entry.date, format: :short) %> •
<%= entry.date ? I18n.l(entry.date, format: :short) : "—" %> •
<%= number_to_currency(entry.amount.abs, unit: Money::Currency.new(entry.currency).symbol) %>
</div>
</div>

View File

@@ -21,7 +21,7 @@
<div class="flex items-center gap-2">
<%= tag.p plaid_item.name, class: "font-medium text-primary" %>
<% if plaid_item.scheduled_for_deletion? %>
<p class="text-destructive text-sm animate-pulse">(deletion in progress...)</p>
<p class="text-destructive text-sm animate-pulse"><%= t(".deletion_in_progress") %></p>
<% end %>
</div>
<% if plaid_item.syncing? %>

View File

@@ -1,35 +1,39 @@
<%# locals: (title:, subtitle: nil, content:, collapsible: false, open: true, auto_open_param: nil, status: nil, meta: nil, actions: nil, badge: nil) %>
<% if collapsible %>
<details <%= "open" if open %>
class="group bg-container shadow-border-xs rounded-xl p-4"
<%= "data-controller=\"auto-open\" data-auto-open-param-value=\"#{h(auto_open_param)}\"".html_safe if auto_open_param.present? %>>
<summary class="flex items-center justify-between gap-2 cursor-pointer rounded-lg list-none [&::-webkit-details-marker]:hidden">
<div class="flex items-center gap-2">
<%= icon "chevron-right", class: "text-secondary group-open:transform group-open:rotate-90 transition-transform" %>
<div>
<div class="flex items-center gap-2 flex-wrap">
<h2 class="text-lg font-medium text-primary"><%= title %></h2>
<%= badge if badge.present? %>
<%= render DS::Disclosure.new(
variant: :card,
open: open,
data: auto_open_param.present? ? { controller: "auto-open", auto_open_param_value: auto_open_param } : nil
) do |disclosure| %>
<% disclosure.with_summary_content do %>
<div class="flex items-center justify-between gap-2 w-full">
<div class="flex items-center gap-2">
<%= icon "chevron-right", class: "text-secondary group-open:rotate-90 motion-safe:transition-transform motion-safe:duration-150" %>
<div>
<div class="flex items-center gap-2 flex-wrap">
<h2 class="text-lg font-medium text-primary"><%= title %></h2>
<%= badge if badge.present? %>
</div>
<% if subtitle.present? %>
<p class="text-secondary text-sm"><%= subtitle %></p>
<% end %>
</div>
<% if subtitle.present? %>
<p class="text-secondary text-sm"><%= subtitle %></p>
<% end %>
</div>
<% if status.present? %>
<div class="flex items-center gap-2 shrink-0 group-open:hidden">
<% if meta.present? %>
<span class="text-xs text-subdued"><%= meta %></span>
<% end %>
<%= status %>
<%= actions if actions.present? %>
</div>
<% end %>
</div>
<% if status.present? %>
<div class="flex items-center gap-2 shrink-0 group-open:hidden">
<% if meta.present? %>
<span class="text-xs text-subdued"><%= meta %></span>
<% end %>
<%= status %>
<%= actions if actions.present? %>
</div>
<% end %>
</summary>
<% end %>
<div class="space-y-4 mt-4">
<%= content %>
</div>
</details>
<% end %>
<% else %>
<section class="bg-container shadow-border-xs rounded-xl p-4 space-y-4">
<div>

View File

@@ -59,7 +59,7 @@
<% if @debug_log_entries.any? %>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-surface-default border-b border-primary">
<thead class="bg-surface border-b border-primary">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-secondary uppercase"><%= t(".table.time") %></th>
<th class="px-4 py-3 text-left text-xs font-medium text-secondary uppercase"><%= t(".table.level") %></th>
@@ -70,7 +70,7 @@
<th class="px-4 py-3 text-left text-xs font-medium text-secondary uppercase"><%= t(".table.metadata") %></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<tbody class="divide-y divide-alpha-black-200 theme-dark:divide-alpha-white-200">
<% @debug_log_entries.each do |entry| %>
<tr>
<td class="px-4 py-3 text-sm text-primary whitespace-nowrap"><%= l(entry.created_at, format: :long) %></td>

View File

@@ -13,17 +13,17 @@
t(".steps.step_5")
] %>
<details class="group bg-surface-inset rounded-xl p-4">
<summary class="list-none cursor-pointer [&::-webkit-details-marker]:hidden">
<%= render DS::Disclosure.new(variant: :card_inset) do |disclosure| %>
<% disclosure.with_summary_content do %>
<div class="flex items-start justify-between gap-3">
<div>
<p class="text-xs font-medium uppercase text-subdued tracking-wider mb-2"><%= t(".flex_query_details.eyebrow") %></p>
<p class="text-sm font-medium text-primary"><%= t(".flex_query_details.title") %></p>
<p class="text-xs text-secondary mt-1"><%= t(".flex_query_details.summary") %></p>
</div>
<%= icon "chevron-down", class: "mt-0.5 text-secondary transition-transform group-open:rotate-180" %>
<%= icon "chevron-down", class: "mt-0.5 text-secondary group-open:rotate-180 motion-safe:transition-transform motion-safe:duration-150" %>
</div>
</summary>
<% end %>
<div class="mt-4 space-y-4 text-sm text-secondary">
<div class="space-y-2">
@@ -89,7 +89,7 @@
<p class="text-xs text-secondary"><%= t(".report_window_note") %></p>
</div>
</details>
<% end %>
<%
ibkr_item = Current.family.ibkr_items.first_or_initialize(name: "Interactive Brokers")

View File

@@ -29,10 +29,12 @@
type: :password %>
<p class="text-xs text-secondary px-1 -mt-1"><%= t("indexa_capital_items.panel.fields.api_token.description") %></p>
<details class="group">
<summary class="text-sm text-secondary cursor-pointer hover:text-primary transition-colors">
<%= t("indexa_capital_items.panel.alternative_auth") %>
</summary>
<%= render DS::Disclosure.new(variant: :inline) do |disclosure| %>
<% disclosure.with_summary_content do %>
<span class="text-sm text-secondary hover:text-primary transition-colors">
<%= t("indexa_capital_items.panel.alternative_auth") %>
</span>
<% end %>
<div class="mt-3 space-y-3 pt-3 border-t border-primary">
<%= form.text_field :username,
label: t("indexa_capital_items.panel.fields.username.label"),
@@ -49,7 +51,7 @@
placeholder: is_new_record ? t("indexa_capital_items.panel.fields.password.placeholder_new") : t("indexa_capital_items.panel.fields.password.placeholder_update"),
type: :password %>
</div>
</details>
<% end %>
<div class="flex justify-end">
<%= form.submit is_new_record ? t("indexa_capital_items.panel.save_button") : t("indexa_capital_items.panel.update_button"),

View File

@@ -57,25 +57,31 @@
<% if items&.any? && items.first.user_registered? %>
<% item = items.first %>
<div class="border-t border-primary pt-4 mt-4">
<details class="group"
data-controller="lazy-load"
data-action="toggle->lazy-load#toggled"
data-lazy-load-url-value="<%= connections_snaptrade_item_path(item) %>"
data-lazy-load-auto-open-param-value="manage">
<summary class="flex items-center justify-between cursor-pointer list-none [&::-webkit-details-marker]:hidden">
<div class="flex items-center gap-2">
<p class="text-sm text-secondary">
<%= t("providers.snaptrade.status_connected", count: item.snaptrade_accounts.count) %>
<% if item.unlinked_accounts_count > 0 %>
<span class="text-warning">(<%= t("providers.snaptrade.needs_setup", count: item.unlinked_accounts_count) %>)</span>
<% end %>
</p>
<%= render DS::Disclosure.new(
variant: :inline,
data: {
controller: "lazy-load",
action: "toggle->lazy-load#toggled",
lazy_load_url_value: connections_snaptrade_item_path(item),
lazy_load_auto_open_param_value: "manage"
}
) do |disclosure| %>
<% disclosure.with_summary_content do %>
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<p class="text-sm text-secondary">
<%= t("providers.snaptrade.status_connected", count: item.snaptrade_accounts.count) %>
<% if item.unlinked_accounts_count > 0 %>
<span class="text-warning">(<%= t("providers.snaptrade.needs_setup", count: item.unlinked_accounts_count) %>)</span>
<% end %>
</p>
</div>
<span class="flex items-center gap-1 text-sm text-secondary hover:text-primary">
<%= t("providers.snaptrade.manage_connections") %>
<%= icon "chevron-right", class: "w-3 h-3 group-open:rotate-90 motion-safe:transition-transform motion-safe:duration-150" %>
</span>
</div>
<span class="flex items-center gap-1 text-sm text-secondary hover:text-primary">
<%= t("providers.snaptrade.manage_connections") %>
<%= icon "chevron-right", class: "w-3 h-3 transition-transform group-open:rotate-90" %>
</span>
</summary>
<% end %>
<div class="mt-3 space-y-3" data-lazy-load-target="content">
<div data-lazy-load-target="loading" class="flex items-center gap-2 text-sm text-secondary py-2">
@@ -86,7 +92,7 @@
<div data-lazy-load-target="frame">
</div>
</div>
</details>
<% end %>
</div>
<% end %>
</div>

View File

@@ -31,7 +31,7 @@
</div>
<span class="text-sm text-secondary">
<%= I18n.l(entry.date, format: :long) %>
<%= entry.date ? I18n.l(entry.date, format: :long) : "—" %>
</span>
<% end %>

View File

@@ -19,7 +19,7 @@
</h3>
<div class="flex items-center gap-2">
<span class="text-sm text-secondary">
<%= I18n.l(entry.date, format: :long) %>
<%= entry.date ? I18n.l(entry.date, format: :long) : "—" %>
</span>
<% if entry.transaction.pending? %>
<span class="inline-flex items-center gap-1 text-xs font-medium rounded-full px-1.5 py-0.5 border border-secondary text-secondary" title="<%= t("transactions.transaction.pending_tooltip") %>">

View File

@@ -19,6 +19,6 @@
</div>
<span class="text-sm text-secondary">
<%= I18n.l(entry.date, format: :long) %>
<%= entry.date ? I18n.l(entry.date, format: :long) : "—" %>
</span>
<% end %>