mirror of
https://github.com/we-promise/sure.git
synced 2026-05-30 15:59:02 +00:00
User flagged two regressions: account colors didn't match between the
goal preview-card avatar stack on the index and the funding-widget
rows on the show page, and the color-picker pen toggle on the new-goal
modal still felt too big.
Color matching:
- `AccountStackComponent` (index card) used
`Goals::AvatarComponent.color_for(account.name)` — MD5-of-name into
the 10-color palette.
- `FundingAccountsBreakdownComponent` (show page) recently switched to
`color_for(account.id.to_s)` — MD5-of-id.
- Same account, two surfaces, two different palette picks. Plus
either hashing scheme can collide within a multi-account goal
(palette has 10 colors).
Move ownership to the Goal model: `Goal#account_color_map` returns
`{ account_id => palette_hex }` for the goal's linked accounts. Sort
by `id` for a stable order across reloads, then assign
`palette[i % palette.size]`. Stable + collision-free up to 10
accounts in a single goal (a realistic upper bound — most goals
link 1-3).
Both consumers now read off the same source:
- `AccountStackComponent.new(accounts:, color_map:)` accepts a hash
and falls back to the name-hash if no map provided (kept for
callers that don't have a goal in scope yet).
- `FundingAccountsBreakdownComponent#color_for` reads
`goal.account_color_map[account.id]`.
- Goal card on index passes `goal.account_color_map` to the stack.
Pen toggle:
The new-goal color-picker pen sat in a `w-5 h-5` circle with a
`border` ring + `text-secondary` icon. The border + secondary text
weight kept it loud against the avatar even at 20px. Drop the
border, drop the size another step (`w-4 h-4`), recolor the icon
`text-subdued` + `hover:text-secondary` so the affordance recedes
when not interacted with. Position shifts from `-bottom-1 -right-1`
(8px overhang) to `-bottom-0.5 -right-0.5` (2px overhang) since the
smaller circle doesn't need the larger float. Icon swaps "pen" for
"pencil" (the more conventional edit indicator across Sure).
28 lines
792 B
Ruby
28 lines
792 B
Ruby
class Goals::AccountStackComponent < ApplicationComponent
|
|
def initialize(accounts:, max: 3, color_map: nil)
|
|
@accounts = accounts
|
|
@max = max
|
|
@color_map = color_map || {}
|
|
end
|
|
|
|
def shown
|
|
@accounts.first(@max)
|
|
end
|
|
|
|
def extra_count
|
|
[ @accounts.size - @max, 0 ].max
|
|
end
|
|
|
|
def initial_for(account)
|
|
account.name.to_s.strip.first&.upcase || "?"
|
|
end
|
|
|
|
# Color for this account, sourced from the per-goal color map when the
|
|
# caller provided one (so the stack on the index card matches the funding
|
|
# widget on the show page). Falls back to the name-hashed palette pick
|
|
# for backward compatibility with any caller that didn't pass `color_map:`.
|
|
def color_for(account)
|
|
@color_map[account.id] || Goals::AvatarComponent.color_for(account.name)
|
|
end
|
|
end
|