diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index 1dd427e8..d3ba7908 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -20,14 +20,14 @@ } .form-field__label { - @apply block text-xs text-gray-500; + @apply block text-xs text-gray-500 peer-disabled:text-gray-400; } .form-field__input { @apply border-none bg-transparent text-sm opacity-100 w-full p-0; @apply focus:opacity-100 focus:outline-none focus:ring-0; @apply placeholder-shown:opacity-50; - @apply disabled:opacity-50; + @apply disabled:text-gray-400; } .form-field__radio { @@ -63,12 +63,16 @@ } select[multiple="multiple"] option { - @apply p-2 rounded-md; + @apply py-2 rounded-md; } select[multiple="multiple"] option:checked { - @apply bg-gray-50; - @apply after:content-['\2713'] after:float-right after:text-gray-500; + @apply after:content-['\2713'] bg-white after:text-gray-500 after:ml-2; + } + + select[multiple="multiple"] option:active, + select[multiple="multiple"] option:focus { + @apply bg-white; } .maybe-switch { diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index accdeab3..ffe890a1 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -17,6 +17,9 @@ class TransactionsController < ApplicationController @entry = Current.family.entries.new(entryable: Account::Transaction.new).tap do |e| if params[:account_id] e.account = Current.family.accounts.find(params[:account_id]) + e.currency = e.account.currency + else + e.currency = Current.family.currency end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d2978dfd..b2c90a2a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -57,6 +57,11 @@ module ApplicationHelper render partial: "shared/drawer", locals: { content: content } end + def disclosure(title, &block) + content = capture &block + render partial: "shared/disclosure", locals: { title: title, content: content } + end + def sidebar_link_to(name, path, options = {}) is_current = current_page?(path) || (request.path.start_with?(path) && path != "/") diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index c5d3d5d5..56b06554 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -10,11 +10,6 @@ module FormsHelper render partial: "shared/modal_form", locals: { title:, subtitle:, content: } end - def form_field_tag(options = {}, &block) - options[:class] = [ "form-field", options[:class] ].compact.join(" ") - tag.div(**options, &block) - end - def radio_tab_tag(form:, name:, value:, label:, icon:, checked: false, disabled: false) form.label name, for: form.field_id(name, value), class: "group has-[:disabled]:cursor-not-allowed" do concat radio_tab_contents(label:, icon:) @@ -27,56 +22,11 @@ module FormsHelper form.select(:period, periods_for_select, { selected: selected }, class: classes, data: { "auto-submit-form-target": "auto" }) end - def money_with_currency_field(form, money_method, options = {}) - render partial: "shared/money_field", locals: { - form: form, - money_method: money_method, - default_currency: options[:default_currency] || "USD", - disable_currency: options[:disable_currency] || false, - hide_currency: options[:hide_currency] || false, - label: options[:label] || "Amount", - required: options[:required] || false - } - end - - def money_field(form, method, options = {}) - value = form.object ? form.object.send(method) : nil - - currency = value&.currency || Money::Currency.new(options[:default_currency] || "USD") - - # See "Monetizable" concern - money_amount_method = method.to_s.chomp("_money").to_sym - - money_options = { - value: value&.amount, - placeholder: "100", - min: -99999999999999, - max: 99999999999999, - step: currency.step - } - - merged_options = options.merge(money_options) - - form.number_field money_amount_method, merged_options - end - - def currency_select_full(form, method, options = {}, html_options = {}, &block) - choices = currencies_for_select.map { |currency| [ "#{currency.name} (#{currency.iso_code})", currency.iso_code ] } - form.select method, choices, options, html_options, &block - end - - def currency_select(form, method, options = {}, html_options = {}, &block) - choices = currencies_for_select.map(&:iso_code) - form.select method, choices, options, html_options, &block + def currencies_for_select + Money::Currency.all_instances.sort_by(&:priority) end private - - def currencies_for_select - Money::Currency.all_instances - .sort_by(&:priority) - end - def radio_tab_contents(label:, icon:) tag.div(class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400 group-has-[:checked]:bg-white group-has-[:checked]:text-gray-800 group-has-[:checked]:shadow-sm") do concat lucide_icon(icon, class: "w-5 h-5") diff --git a/app/helpers/styled_form_builder.rb b/app/helpers/styled_form_builder.rb index e730b453..6da18c39 100644 --- a/app/helpers/styled_form_builder.rb +++ b/app/helpers/styled_form_builder.rb @@ -6,53 +6,69 @@ class StyledFormBuilder < ActionView::Helpers::FormBuilder text_field_helpers.each do |selector| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{selector}(method, options = {}) - input_html = label_html(method, options) + super(method, merged_options(options)) - input_html = apply_form_field_wrapper(input_html) unless options[:inline] - input_html + merged_options = { class: "form-field__input" }.merge(options) + label = build_label(method, options) + field = super(method, merged_options) + + build_styled_field(label, field, merged_options) end RUBY_EVAL end def radio_button(method, tag_value, options = {}) - super(method, tag_value, merged_options(options, "form-field__radio")) + merged_options = { class: "form-field__radio" }.merge(options) + + super(method, tag_value, merged_options) end def select(method, choices, options = {}, html_options = {}) - input_html = label_html(method, options) + super(method, choices, options, merged_options(html_options)) - input_html = apply_form_field_wrapper(input_html, class: "pr-0") unless options[:inline] - input_html + merged_html_options = { class: "form-field__input" }.merge(html_options) + + label = build_label(method, options) + field = super(method, choices, options, merged_html_options) + + build_styled_field(label, field, options, remove_padding_right: true) end def collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) - input_html = label_html(method, options) + super(method, collection, value_method, text_method, options, merged_options(html_options)) - input_html = apply_form_field_wrapper(input_html, class: "pr-0") unless options[:inline] - input_html + merged_html_options = { class: "form-field__input" }.merge(html_options) + + label = build_label(method, options) + field = super(method, collection, value_method, text_method, options, merged_html_options) + + build_styled_field(label, field, options, remove_padding_right: true) + end + + def money_field(amount_method, currency_method, options = {}) + @template.render partial: "shared/money_field", locals: { + form: self, + amount_method:, + currency_method:, + **options + } end def submit(value = nil, options = {}) + merged_options = { class: "form-field__submit" }.merge(options) value, options = nil, value if value.is_a?(Hash) - super(value, merged_options(options, "form-field__submit")) + super(value, merged_options) end private - def apply_form_field_wrapper(input_html, **options) - @template.form_field_tag(**options) do - input_html + def build_styled_field(label, field, options, remove_padding_right: false) + if options[:inline] + label + field + else + @template.tag.div class: [ "form-field", options[:container_class], ("pr-0" if remove_padding_right) ] do + label + field + end end end - def merged_options(options, default_class = "form-field__input") - combined_classes = options.fetch(:class, "") + " #{default_class}" - style_options = { class: combined_classes } - non_custom_options = options.except(:class, :label, :inline) - style_options.merge(non_custom_options) - end - - def label_html(method, options) - return label(method, class: "form-field__label") if options[:label] == true + def build_label(method, options) return "".html_safe unless options[:label] - + return label(method, class: "form-field__label") if options[:label] == true label(method, options[:label], class: "form-field__label") end end diff --git a/app/javascript/controllers/money_field_controller.js b/app/javascript/controllers/money_field_controller.js index 26219681..70ef4bfe 100644 --- a/app/javascript/controllers/money_field_controller.js +++ b/app/javascript/controllers/money_field_controller.js @@ -13,7 +13,6 @@ export default class extends Controller { updateAmount(currency) { (new CurrenciesService).get(currency).then((currency) => { - console.log(currency) this.amountTarget.step = currency.step; if (isFinite(this.amountTarget.value)) { diff --git a/app/views/account/trades/_form.html.erb b/app/views/account/trades/_form.html.erb index a6a9168c..2e6e7881 100644 --- a/app/views/account/trades/_form.html.erb +++ b/app/views/account/trades/_form.html.erb @@ -2,7 +2,7 @@ <%= styled_form_with data: { turbo_frame: "_top", controller: "trade-form" }, scope: :account_entry, - url: entry.new_record? ? account_trades_path(entry.account) : account_entry_path(entry.account, entry) do |form| %> + url: account_trades_path(entry.account) do |form| %>
<%= t(".exclude_subtitle") %>
-<%= t(".delete_subtitle") %>
-<%= t(".exclude_subtitle") %>
+<%= t(".delete_subtitle") %>
+