Expand budgeting icon options (#341)

* Expand budgeting icon options

* Reorder/compact

* Underscore in parent_category and lucide_icon

* Display category parent on delete/reassign

* Add scrolling on mobile

* Icon name fix

* Already i18n, why not?
This commit is contained in:
Juan José Mata
2025-12-12 16:05:53 +01:00
committed by GitHub
parent dd461faf84
commit 3e5dfc0263
6 changed files with 31 additions and 21 deletions

View File

@@ -17,6 +17,12 @@ class Category < ApplicationRecord
before_save :inherit_color_from_parent
scope :alphabetically, -> { order(:name) }
scope :alphabetically_by_hierarchy, -> {
left_joins(:parent)
.order(Arel.sql("COALESCE(parents_categories.name, categories.name)"))
.order(Arel.sql("parents_categories.name IS NOT NULL"))
.order(:name)
}
scope :roots, -> { where(parent_id: nil) }
scope :incomes, -> { where(classification: "income") }
scope :expenses, -> { where(classification: "expense") }
@@ -48,18 +54,18 @@ class Category < ApplicationRecord
class << self
def icon_codes
%w[
ambulance apple award baby banknote barcode bath battery bed-single beer bike
bluetooth bone book book-open briefcase building bus cake calculator camera
car cat circle-dollar-sign coffee coins compass cookie cooking-pot credit-card
dices dog drama drill droplet drum dumbbell film flame flower fuel gamepad-2
gift glasses globe graduation-cap hammer hand-helping headphones heart
heart-pulse home house ice-cream-cone key landmark laptop leaf lightbulb
luggage mail map-pin mic monitor moon music package palette paw-print pen
pencil phone piggy-bank pill pizza plane plug power printer puzzle receipt
ribbon scale scissors settings shield shield-plus shirt shopping-bag
shopping-cart smartphone sparkles sprout stethoscope store sun tag target
tent thermometer ticket train trees trophy truck tv umbrella users utensils
video wallet waves wifi wine wrench zap
ambulance apple award baby badge-dollar-sign banknote barcode bar-chart-3
bath battery bed-single beer bike bluetooth bone book-open briefcase building
bus cake calculator calendar-range camera car cat circle-dollar-sign coffee
coins compass cookie cooking-pot credit-card dices dog drama drill droplet
drum dumbbell film flame flower fuel gamepad-2 gift glasses globe graduation-cap
hammer hand-helping headphones heart heart-pulse home ice-cream-cone key
landmark laptop leaf lightbulb chart-line luggage mail map-pin mic monitor moon
music package palette paw-print pencil percent phone pie-chart piggy-bank pill
pizza plane plug power printer puzzle receipt receipt-text ribbon scale scissors
settings shield shirt shopping-bag shopping-cart smartphone sparkles sprout
stethoscope store sun tag target tent thermometer ticket train trees trophy truck
tv umbrella users utensils video wallet wallet-cards waves wifi wine wrench zap
]
end
@@ -93,7 +99,7 @@ class Category < ApplicationRecord
[ "Entertainment", "#a855f7", "drama", "expense" ],
[ "Healthcare", "#4da568", "pill", "expense" ],
[ "Personal Care", "#14b8a6", "scissors", "expense" ],
[ "Home Improvement", "#d97706", "house", "expense" ],
[ "Home Improvement", "#d97706", "hammer", "expense" ],
[ "Mortgage / Rent", "#b45309", "home", "expense" ],
[ "Utilities", "#eab308", "lightbulb", "expense" ],
[ "Subscriptions", "#6366f1", "wifi", "expense" ],
@@ -130,6 +136,10 @@ class Category < ApplicationRecord
parent.present?
end
def name_with_parent
subcategory? ? "#{parent.name} > #{name}" : name
end
private
def category_level_limit
if (subcategory? && parent.subcategory?) || (parent? && subcategory?)

View File

@@ -47,7 +47,7 @@ class CategoryImport < Import
def csv_template
template = <<-CSV
name*,color,parent_category,classification,lucide-icon
name*,color,parent_category,classification,lucide_icon
Food & Drink,#f97316,,expense,carrot
Groceries,#407706,Food & Drink,expense,shopping-basket
Salary,#22c55e,,income,briefcase
@@ -65,7 +65,7 @@ class CategoryImport < Import
category_color: row["color"].to_s.strip,
category_parent: row["parent_category"].to_s.strip,
category_classification: row["classification"].to_s.strip,
category_icon: (row["lucide-icon"].presence || row["icon"]).to_s.strip,
category_icon: (row["lucide_icon"].presence || row["icon"]).to_s.strip,
currency: default_currency
)
end

View File

@@ -27,7 +27,7 @@ class Investment < ApplicationRecord
end
def icon
"line-chart"
"chart-line"
end
end
end

View File

@@ -42,7 +42,7 @@
<div class="flex flex-wrap gap-2 justify-center flex-col w-auto md:w-87">
<h4 class="text-secondary text-sm">Icon</h4>
<div class="flex flex-wrap gap-0.5">
<div class="flex flex-wrap gap-0.5 max-h-52 overflow-auto">
<% Category.icon_codes.each do |icon| %>
<label class="relative">
<%= f.radio_button :lucide_icon, icon, class: "sr-only peer", data: { action: "change->category#handleIconChange change->category#handleIconColorChange", category_target:"icon" } %>

View File

@@ -9,8 +9,8 @@
deletion_submit_text_when_not_replacing_value: t(".delete_and_leave_uncategorized", category_name: @category.name),
deletion_submit_text_when_replacing_value: t(".delete_and_recategorize", category_name: @category.name) } do |f| %>
<%= f.collection_select :replacement_category_id,
Current.family.categories.alphabetically.without(@category),
:id, :name,
Current.family.categories.alphabetically_by_hierarchy.without(@category),
:id, :name_with_parent,
{ prompt: t(".replacement_category_prompt"), label: t(".category"), container_class: "mb-4" },
data: { deletion_target: "replacementField", action: "deletion#chooseSubmitButton" } %>
@@ -22,7 +22,7 @@
) %>
<%= render DS::Button.new(
text: "Delete and reassign",
text: t(".delete_and_recategorize", category_name: @category.name),
data: { deletion_target: "safeSubmitButton" },
hidden: true,
full_width: true

View File

@@ -96,7 +96,7 @@
</div>
<div class="flex flex-col gap-4 items-center">
<%= render DS::FilledIcon.new(icon: "line-chart", variant: :surface) %>
<%= render DS::FilledIcon.new(icon: "chart-line", variant: :surface) %>
<p class="text-sm text-primary text-center">Performance and investment returns across portfolio</p>
</div>