1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 15:35:22 +02:00

Centralize all disclosure instances

This commit is contained in:
Zach Gollwitzer 2025-04-28 23:48:56 -04:00
parent db3953825f
commit 779ca08d95
18 changed files with 86 additions and 145 deletions

View file

@ -0,0 +1,25 @@
<details class="group" <%= "open" if open %>>
<%= tag.summary class: class_names(
"px-3 py-2 rounded-xl cursor-pointer flex items-center justify-between bg-surface"
) do %>
<div class="flex items-center gap-3">
<% if align == :left %>
<%= lucide_icon "chevron-right", class: "fg-gray w-5 h-5 group-open:transform group-open:rotate-90" %>
<% end %>
<%= tag.span class: class_names("font-medium", align == :left ? "text-sm text-primary" : "text-xs uppercase text-secondary") do %>
<%= title %>
<% end %>
</div>
<% if align == :right %>
<%= lucide_icon "chevron-down", class: "fg-gray w-5 h-5 group-open:transform group-open:rotate-180" %>
<% elsif summary_content? %>
<%= summary_content %>
<% end %>
<% end %>
<div class="mt-2">
<%= content %>
</div>
</details>

View file

@ -0,0 +1,12 @@
class DisclosureComponent < ViewComponent::Base
renders_one :summary_content
attr_reader :title, :align, :open, :opts
def initialize(title:, align: "right", open: false, **opts)
@title = title
@align = align.to_sym
@open = open
@opts = opts
end
end

View file

@ -70,11 +70,6 @@ module ApplicationHelper
render partial: "shared/drawer", locals: { content:, reload_on_close: }
end
def disclosure(title, default_open: true, &block)
content = capture &block
render partial: "shared/disclosure", locals: { title: title, content: content, open: default_open }
end
def page_active?(path)
current_page?(path) || (request.path.start_with?(path) && path != "/")
end

View file

@ -1,51 +0,0 @@
import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="account-collapse"
export default class extends Controller {
static values = { type: String };
initialToggle = false;
STORAGE_NAME = "accountCollapseStates";
connect() {
this.element.addEventListener("toggle", this.onToggle);
this.updateFromLocalStorage();
}
disconnect() {
this.element.removeEventListener("toggle", this.onToggle);
}
onToggle = () => {
if (this.initialToggle) {
this.initialToggle = false;
return;
}
const items = this.getItemsFromLocalStorage();
if (items.has(this.typeValue)) {
items.delete(this.typeValue);
} else {
items.add(this.typeValue);
}
localStorage.setItem(this.STORAGE_NAME, JSON.stringify([...items]));
};
updateFromLocalStorage() {
const items = this.getItemsFromLocalStorage();
if (items.has(this.typeValue)) {
this.initialToggle = true;
this.element.setAttribute("open", "");
}
}
getItemsFromLocalStorage() {
try {
const items = localStorage.getItem(this.STORAGE_NAME);
return new Set(items ? JSON.parse(items) : []);
} catch (error) {
console.error("Error parsing items from localStorage:", error);
return new Set();
}
}
}

View file

@ -40,7 +40,7 @@
class: "justify-start"
) %>
<div class="space-y-2">
<div>
<% family.balance_sheet.account_groups("asset").each do |group| %>
<%= render "accounts/accountable_group", account_group: group %>
<% end %>
@ -60,7 +60,7 @@
class: "justify-start"
) %>
<div class="space-y-2">
<div>
<% family.balance_sheet.account_groups("liability").each do |group| %>
<%= render "accounts/accountable_group", account_group: group %>
<% end %>
@ -80,7 +80,7 @@
class: "justify-start"
) %>
<div class="space-y-2">
<div>
<% family.balance_sheet.account_groups.each do |group| %>
<%= render "accounts/accountable_group", account_group: group %>
<% end %>

View file

@ -1,11 +1,7 @@
<%# locals: (account_group:) %>
<details class="group" data-controller="account-collapse" data-account-collapse-type-value="<%= account_group.key %>">
<summary class="px-3 py-2 flex items-center gap-3 cursor-pointer h-10 mb-1">
<%= icon("chevron-right", class: "group-open:rotate-90") %>
<%= tag.p account_group.name, class: "text-sm font-medium" %>
<%= render DisclosureComponent.new(title: account_group.name, align: :left) do |disclosure| %>
<% disclosure.with_summary_content do %>
<div class="ml-auto text-right grow">
<%= tag.p format_money(account_group.total_money), class: "text-sm font-medium text-primary" %>
@ -15,7 +11,7 @@
</div>
<% end %>
</div>
</summary>
<% end %>
<div class="space-y-1">
<% account_group.accounts.each do |account| %>
@ -49,4 +45,4 @@
frame: :modal,
class: "justify-start"
) %>
</details>
<% end %>

View file

@ -10,7 +10,7 @@
<% else %>
<div class="w-8 h-8 group-hover:scale-105 transition-all duration-300 rounded-full flex justify-center items-center" style="<%= mixed_hex_styles(budget_category.category.color) %>">
<% if budget_category.category.lucide_icon %>
<%= icon(budget_category.category.lucide_icon) %>
<%= icon(budget_category.category.lucide_icon, color: "current") %>
<% else %>
<%= render "shared/circle_logo", name: budget_category.category.name, hex: budget_category.category.color %>
<% end %>

View file

@ -26,13 +26,7 @@
<% end %>
</header>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2
text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4>Overview</h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<%= render DisclosureComponent.new(title: "Overview", open: true) do %>
<div class="pb-4">
<dl class="space-y-3 px-3 py-2">
<div class="flex items-center justify-between text-sm">
@ -91,15 +85,9 @@
</div>
</dl>
</div>
</details>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2
text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4>Recent Transactions</h4>
<%= icon "chevron-down", size: "sm", class: "group-open:transform group-open:rotate-180" %>
</summary>
<% end %>
<%= render DisclosureComponent.new(title: "Recent Transactions", open: true) do %>
<div class="space-y-2">
<div class="px-3 py-4 space-y-2">
<% if @recent_transactions.any? %>
@ -149,6 +137,6 @@
<% end %>
</div>
</div>
</details>
<% end %>
</div>
<% end %>

View file

@ -9,12 +9,7 @@
<%= image_tag "https://logo.synthfinance.com/ticker/#{@holding.ticker}", loading: "lazy", class: "w-9 h-9 rounded-full" %>
</header>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4><%= t(".overview") %></h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<%= render DisclosureComponent.new(title: t(".overview"), open: true) do %>
<div class="pb-4">
<dl class="space-y-3 px-3 py-2">
<div class="flex items-center justify-between text-sm">
@ -45,14 +40,9 @@
</div>
</dl>
</div>
</details>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4><%= t(".history") %></h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<% end %>
<%= render DisclosureComponent.new(title: t(".history"), open: true) do %>
<div class="space-y-2">
<div class="px-3 py-4">
<% if @holding.trades.any? %>
@ -85,15 +75,10 @@
<% end %>
</div>
</div>
</details>
<% end %>
<% unless @holding.account.plaid_account_id.present? %>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4><%= t(".settings") %></h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<%= render DisclosureComponent.new(title: t(".settings"), open: true) do %>
<div class="pb-4">
<div class="flex items-center justify-between gap-2 p-3">
<div class="text-sm space-y-1">
@ -108,7 +93,7 @@
data: { turbo_confirm: true } %>
</div>
</div>
</details>
<% end %>
<% end %>
</div>
<% end %>

View file

@ -1,11 +0,0 @@
<%# locals: (title:, content:, open: true) %>
<details class="group space-y-2" <%= "open" if open %>>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium
uppercase text-secondary bg-surface focus-visible:outline-hidden">
<h3><%= title %></h3>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<%= content %>
</details>

View file

@ -26,7 +26,7 @@
<% trade = entry.trade %>
<div class="mb-2">
<%= disclosure t(".overview") do %>
<%= render DisclosureComponent.new(title: t(".overview"), open: true) do %>
<div class="pb-4">
<dl class="space-y-3 px-3 py-2">
<div class="flex items-center justify-between text-sm">

View file

@ -5,7 +5,7 @@
<div class="space-y-2">
<!-- Details Section -->
<%= disclosure t(".details") do %>
<%= render DisclosureComponent.new(title: t(".details")) do %>
<div class="pb-4">
<%= styled_form_with model: @entry,
url: trade_path(@entry),
@ -43,7 +43,7 @@
<% end %>
<!-- Additional Section -->
<%= disclosure t(".additional") do %>
<%= render DisclosureComponent.new(title: t(".additional")) do %>
<div class="pb-4">
<%= styled_form_with model: @entry,
url: trade_path(@entry),
@ -59,7 +59,7 @@
<% end %>
<!-- Settings Section -->
<%= disclosure t(".settings") do %>
<%= render DisclosureComponent.new(title: t(".settings")) do %>
<div class="pb-4">
<!-- Exclude Trade Form -->
<%= styled_form_with model: @entry,

View file

@ -27,7 +27,7 @@
<%= f.date_field :date, label: t(".date"), required: true, min: Entry.min_supported_date, max: Date.current, value: Date.current %>
</section>
<%= disclosure t(".details"), default_open: false do %>
<%= render DisclosureComponent.new(title: t(".details")) do %>
<%= f.fields_for :entryable do |ef| %>
<%= ef.select :tag_ids,
Current.family.tags.alphabetically.pluck(:name, :id),

View file

@ -18,30 +18,20 @@
</header>
<div class="space-y-2">
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4>Overview</h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<%= render DisclosureComponent.new(title: "Overview", open: true) do %>
<div class="pb-6 space-y-2">
<%= form.date_field :date, label: "Date", max: Date.current %>
</div>
</details>
<details class="group space-y-2" open>
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
<h4>Details</h4>
<%= icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
</summary>
<% end %>
<%= render DisclosureComponent.new(title: "Details", open: true) do %>
<div class="space-y-2">
<%= form.collection_select :category_id, Current.family.categories.alphabetically, :id, :name, { prompt: "Select a category", label: "Category", class: "text-subdued" } %>
<%= form.collection_select :merchant_id, Current.family.merchants.alphabetically, :id, :name, { prompt: "Select a merchant", label: "Merchant", class: "text-subdued" } %>
<%= form.select :tag_ids, Current.family.tags.alphabetically.pluck(:name, :id), { include_blank: "None", multiple: true, label: "Tags", container_class: "h-40" } %>
<%= form.text_area :notes, label: "Notes", placeholder: "Enter a note that will be applied to selected transactions", rows: 5 %>
</div>
</details>
<% end %>
</div>
</div>
</div>

View file

@ -3,7 +3,7 @@
<div class="space-y-2">
<!-- Overview Section -->
<%= disclosure t(".overview") do %>
<%= render DisclosureComponent.new(title: t(".overview"), open: true) do %>
<div class="pb-4">
<%= styled_form_with model: @entry,
url: transaction_path(@entry),
@ -48,7 +48,7 @@
<% end %>
<!-- Details Section -->
<%= disclosure t(".details"), default_open: false do %>
<%= render DisclosureComponent.new(title: t(".details")) do %>
<div class="pb-4">
<%= styled_form_with model: @entry,
url: transaction_path(@entry),
@ -96,9 +96,8 @@
<% end %>
<!-- Settings Section -->
<%= disclosure t(".settings") do %>
<%= render DisclosureComponent.new(title: t(".settings")) do %>
<div class="pb-4">
<%= styled_form_with model: @entry,
url: transaction_path(@entry),
class: "p-3",

View file

@ -21,7 +21,7 @@
<div class="space-y-2">
<!-- Overview Section -->
<%= disclosure t(".overview") do %>
<%= render DisclosureComponent.new(title: t(".overview"), open: true) do %>
<div class="pb-4 px-3 pt-2 text-sm space-y-3 text-primary">
<div class="space-y-3">
<dl class="flex items-center gap-2 justify-between">
@ -68,7 +68,7 @@
<% end %>
<!-- Details Section -->
<%= disclosure t(".details") do %>
<%= render DisclosureComponent.new(title: t(".details")) do %>
<%= styled_form_with model: @transfer,
data: { controller: "auto-submit-form" }, class: "space-y-2" do |f| %>
<% if @transfer.categorizable? %>
@ -84,7 +84,7 @@
<% end %>
<!-- Settings Section -->
<%= disclosure t(".settings") do %>
<%= render DisclosureComponent.new(title: t(".settings")) do %>
<div class="pb-4">
<div class="flex items-center justify-between gap-2 p-3">
<div class="text-sm space-y-1">

View file

@ -5,7 +5,7 @@
<div class="space-y-2">
<!-- Overview Section -->
<%= disclosure t(".overview") do %>
<%= render DisclosureComponent.new(title: t(".overview"), open: true) do %>
<div class="pb-4">
<%= styled_form_with model: entry,
url: entry_path(entry),
@ -30,7 +30,7 @@
<% end %>
<!-- Details Section -->
<%= disclosure t(".details") do %>
<%= render DisclosureComponent.new(title: t(".details")) do %>
<div class="pb-4">
<%= styled_form_with model: entry,
url: entry_path(entry),
@ -46,7 +46,7 @@
<% end %>
<!-- Settings Section -->
<%= disclosure t(".settings") do %>
<%= render DisclosureComponent.new(title: t(".settings")) do %>
<div class="pb-4">
<!-- Delete Valuation Form -->
<div class="flex items-center justify-between gap-2 p-3">

View file

@ -0,0 +1,13 @@
class DisclosureComponentPreview < ViewComponent::Preview
# @display container_classes max-w-[400px]
# @param align select ["left", "right"]
def default(align: "right")
render DisclosureComponent.new(title: "Title", align: align, open: true) do |disclosure|
disclosure.with_summary_content do
content_tag(:p, "$200.25", class: "text-xs font-mono font-medium")
end
content_tag(:p, "Sample disclosure content", class: "text-sm")
end
end
end