1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-21 22:29:38 +02:00

Fix merchants color picker (#1134)

* Fix merchants color picker

* Lint fixes
This commit is contained in:
Zach Gollwitzer 2024-08-26 19:18:27 -04:00 committed by GitHub
parent 166ed4b1ea
commit f82ce59dad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 52 additions and 71 deletions

View file

@ -6,7 +6,7 @@ module MenusHelper
end end
end end
def contextual_menu_modal_action_item(label, url, icon: "pencil-line", turbo_frame: nil) def contextual_menu_modal_action_item(label, url, icon: "pencil-line", turbo_frame: :modal)
link_to url, class: "flex items-center rounded-lg text-gray-900 hover:bg-gray-50 py-2 px-3 gap-2", data: { turbo_frame: } do link_to url, class: "flex items-center rounded-lg text-gray-900 hover:bg-gray-50 py-2 px-3 gap-2", data: { turbo_frame: } do
concat(lucide_icon(icon, class: "shrink-0 w-5 h-5 text-gray-500")) concat(lucide_icon(icon, class: "shrink-0 w-5 h-5 text-gray-500"))
concat(tag.span(label, class: "text-sm")) concat(tag.span(label, class: "text-sm"))

View file

@ -1,32 +1,29 @@
import {Controller} from "@hotwired/stimulus"; import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="merchant-avatar" // Connects to data-controller="merchant-avatar"
// Used by the transaction merchant form to show a preview of what the avatar will look like // Used by the transaction merchant form to show a preview of what the avatar will look like
export default class extends Controller { export default class extends Controller {
static targets = [ static targets = [
"name", "name",
"color",
"avatar" "avatar"
]; ];
connect() { connect() {
this.nameTarget.addEventListener("input", this.handleNameChange); this.nameTarget.addEventListener("input", this.handleNameChange);
this.colorTarget.addEventListener("input", this.handleColorChange);
} }
disconnect() { disconnect() {
this.nameTarget.removeEventListener("input", this.handleNameChange); this.nameTarget.removeEventListener("input", this.handleNameChange);
this.colorTarget.removeEventListener("input", this.handleColorChange);
} }
handleNameChange = (e) => { handleNameChange = (e) => {
this.avatarTarget.textContent = (e.currentTarget.value?.[0] || "?").toUpperCase(); this.avatarTarget.textContent = (e.currentTarget.value?.[0] || "?").toUpperCase();
} }
handleColorChange = (e) => { handleColorChange(e) {
const color = e.currentTarget.value; const color = e.currentTarget.value;
this.avatarTarget.style.backgroundColor = `color-mix(in srgb, ${color} 5%, white)`; this.avatarTarget.style.backgroundColor = `color-mix(in srgb, ${color} 5%, white)`;
this.avatarTarget.style.borderColor = `color-mix(in srgb, ${color} 10%, white)`; this.avatarTarget.style.borderColor = `color-mix(in srgb, ${color} 10%, white)`;
this.avatarTarget.style.color = color; this.avatarTarget.style.color = color;
} }
} }

View file

@ -1,19 +1,16 @@
<% is_editing = @merchant.id.present? %>
<div data-controller="merchant-avatar"> <div data-controller="merchant-avatar">
<%= styled_form_with model: @merchant, url: is_editing ? merchant_path(@merchant) : merchants_path, method: is_editing ? :patch : :post, scope: :merchant, class: "space-y-4", data: { turbo: false } do |f| %> <%= styled_form_with model: @merchant, class: "space-y-4", data: { turbo: false } do |f| %>
<section class="space-y-4"> <section class="space-y-4">
<div class="w-fit m-auto"> <div class="w-fit m-auto">
<%= render partial: "merchants/avatar", locals: { merchant: } %> <%= render partial: "merchants/avatar", locals: { merchant: @merchant } %>
</div> </div>
<div data-controller="select" data-select-active-class="bg-gray-200" data-select-selected-value="<%= @merchant&.color || Merchant::COLORS[0] %>"> <div class="flex gap-2 items-center justify-center">
<%= f.hidden_field :color, data: { select_target: "input", merchant_avatar_target: "color" } %> <% Merchant::COLORS.each do |color| %>
<ul data-select-target="list" class="flex gap-2 items-center"> <label class="relative">
<% Merchant::COLORS.each do |color| %> <%= f.radio_button :color, color, class: "sr-only peer", data: { action: "change->merchant-avatar#handleColorChange" } %>
<li tabindex="0" data-select-target="option" data-action="click->select#selectOption" data-value="<%= color %>" class="flex shrink-0 justify-center items-center w-6 h-6 cursor-pointer hover:bg-gray-200 rounded-full"> <div class="w-6 h-6 rounded-full cursor-pointer peer-checked:ring-2 peer-checked:ring-offset-2 peer-checked:ring-blue-500" style="background-color: <%= color %>"></div>
<div style="background-color: <%= color %>" class="shrink-0 w-4 h-4 rounded-full"></div> </label>
</li> <% end %>
<% end %>
</ul>
</div> </div>
<div class="relative flex items-center border border-gray-200 rounded-lg"> <div class="relative flex items-center border border-gray-200 rounded-lg">
<%= f.text_field :name, placeholder: t(".name_placeholder"), class: "text-sm font-normal placeholder:text-gray-500 h-10 relative pl-3 w-full border-none rounded-lg", required: true, data: { merchant_avatar_target: "name" } %> <%= f.text_field :name, placeholder: t(".name_placeholder"), class: "text-sm font-normal placeholder:text-gray-500 h-10 relative pl-3 w-full border-none rounded-lg", required: true, data: { merchant_avatar_target: "name" } %>
@ -21,7 +18,7 @@
</section> </section>
<section> <section>
<%= f.submit(is_editing ? t(".submit_edit") : t(".submit_create")) %> <%= f.submit %>
</section> </section>
<% end %> <% end %>
</div> </div>

View file

@ -1,41 +0,0 @@
<%# locals: (merchants:) %>
<% merchants.each.with_index do |merchant, index| %>
<div class="flex justify-between items-center p-4 bg-white">
<div class="flex w-full items-center gap-2.5">
<%= render partial: "merchants/avatar", locals: { merchant: } %>
<p class="text-gray-900 text-sm truncate">
<%= merchant.name %>
</p>
</div>
<div class="relative cursor-pointer" data-controller="menu">
<button data-menu-target="button" class="flex hover:bg-gray-100 p-2 rounded">
<%= lucide_icon("more-horizontal", class: "w-5 h-5 text-gray-500") %>
</button>
<div data-menu-target="content" class="absolute z-10 top-10 right-0 border border-alpha-black-25 bg-white rounded-lg shadow-xs w-48 hidden">
<div class="border-t border-b border-alpha-black-100 p-1">
<%= button_to edit_merchant_path(merchant),
method: :get,
class: "flex w-full gap-1 items-center text-sm hover:bg-gray-50 rounded-lg px-3 py-2",
data: { turbo_frame: "modal" } do %>
<%= lucide_icon("pencil-line", class: "w-5 h-5 mr-2") %> <%= t(".edit") %>
<% end %>
<%= button_to merchant_path(merchant),
method: :delete,
class: "flex w-full gap-1 items-center text-sm text-red-600 hover:text-red-800 hover:bg-gray-50 rounded-lg px-3 py-2",
data: {
turbo_confirm: {
title: t(".confirm_title"),
body: t(".confirm_body"),
accept: t(".confirm_accept")
}
} do %>
<%= lucide_icon("trash-2", class: "w-5 h-5 mr-1") %> <%= t(".delete") %>
<% end %>
</div>
</div>
</div>
</div>
<% unless index == merchants.size - 1 %>
<div class="h-px bg-alpha-black-50 ml-14 mr-6"></div>
<% end %>
<% end %>

View file

@ -0,0 +1,26 @@
<%# locals: (merchant:) %>
<div class="flex justify-between items-center p-4 bg-white">
<div class="flex w-full items-center gap-2.5">
<%= render partial: "merchants/avatar", locals: { merchant: } %>
<p class="text-gray-900 text-sm truncate">
<%= merchant.name %>
</p>
</div>
<div class="justify-self-end">
<%= contextual_menu do %>
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
<%= contextual_menu_modal_action_item t(".edit"), edit_merchant_path(merchant) %>
<%= contextual_menu_destructive_item t(".delete"),
merchant_path(merchant),
turbo_frame: "_top",
turbo_confirm: {
title: t(".confirm_title"),
body: t(".confirm_body"),
accept: t(".confirm_accept")
} %>
</div>
<% end %>
</div>
</div>

View file

@ -0,0 +1,3 @@
<div class="bg-white">
<div class="h-px bg-alpha-black-50 ml-14 mr-6"></div>
</div>

View file

@ -8,7 +8,7 @@
<%= link_to new_merchant_path, class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %> <%= link_to new_merchant_path, class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %> <%= lucide_icon("plus", class: "w-5 h-5") %>
<span><%= t(".new_short") %></span> <span><%= t(".new") %></span>
<% end %> <% end %>
</div> </div>
<div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4"> <div class="bg-white shadow-xs border border-alpha-black-25 rounded-xl p-4">
@ -18,18 +18,20 @@
<p class="text-gray-900 mb-1 font-medium text-sm"><%= t(".empty") %></p> <p class="text-gray-900 mb-1 font-medium text-sm"><%= t(".empty") %></p>
<%= link_to new_merchant_path, class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %> <%= link_to new_merchant_path, class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %> <%= lucide_icon("plus", class: "w-5 h-5") %>
<span><%= t(".new_long") %></span> <span><%= t(".new") %></span>
<% end %> <% end %>
</div> </div>
</div> </div>
<% else %> <% else %>
<div class="bg-gray-25 p-1 rounded-xl"> <div class="bg-gray-25 p-1 rounded-xl">
<div class="flex items-center px-4 py-2 text-xs font-medium text-gray-500"> <div class="flex items-center gap-1.5 px-4 py-2 text-xs font-medium text-gray-500">
<p><%= t(".title") %></p> <p><%= t(".title") %></p>
<span class="text-gray-400 mx-2">&middot;</span> <span class="text-gray-400">&middot;</span>
<p><%= @merchants.count %></p> <p><%= @merchants.count %></p>
</div> </div>
<%= render partial: "merchants/list", locals: { merchants: @merchants } %> <div class="overflow-hidden rounded-lg">
<%= render partial: @merchants, spacer_template: "merchants/ruler" %>
</div>
</div> </div>
<% end %> <% end %>
</div> </div>

View file

@ -9,14 +9,11 @@ en:
title: Edit merchant title: Edit merchant
form: form:
name_placeholder: Merchant name name_placeholder: Merchant name
submit_create: Add merchant
submit_edit: Update
index: index:
empty: No merchants yet empty: No merchants yet
new_long: New merchant new: New merchant
new_short: New
title: Merchants title: Merchants
list: merchant:
confirm_accept: Delete merchant confirm_accept: Delete merchant
confirm_body: Are you sure you want to delete this merchant? Removing this merchant confirm_body: Are you sure you want to delete this merchant? Removing this merchant
will unlink all associated transactions and may effect your reporting. will unlink all associated transactions and may effect your reporting.