mirror of
https://github.com/we-promise/sure.git
synced 2026-05-30 07:49:01 +00:00
ux(goals): catch-up rework, dark-mode pill contrast, color disclosure, stepper continue-right
- catch_up alert: title now leads with the new info (delta) and body
states the required rate. Was "Save $1,000/mo to catch up" + "Currently
$750/mo behind" — confusingly double-stated. Now "Behind by $750/mo" +
"Save $1,000/mo to stay on track for {date}." Locale keys swap the
%{amount}/%{delta} placement.
- Goals::StatusPillComponent: each variant carries a theme-dark: text
override so the dark-700 text doesn't disappear against the dark-mode
tinted surface. Verified in dark mode: Paused pill text is now
rgb(231,231,231) (gray-200) instead of rgb(54,54,54) (gray-700).
Pre-existing token contrast fix tracked at we-promise/sure#1736 stays
the long-term path; this is the local workaround that doesn't drop
4.5:1 in either theme.
- New goals/_color_picker.html.erb partial: <details> disclosure with
current-color preview in the summary + swatch grid in the popover.
Mirrors the categories form's pen-icon-overlay pattern in spirit
(collapsed by default; user clicks to expand). Both _form_edit and
_form_stepper render the partial; the stepper's hidden color field is
replaced by the visible disclosure.
- Stepper footer: change `justify-between` to `flex items-center` plus
`ml-auto` on the Continue wrapper. Continue now sits right-aligned in
step 1 (where Back is hidden) and stays right in step 2 with Back
taking the left edge.
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
class Goals::StatusPillComponent < ApplicationComponent
|
||||
# Text colors here intentionally use palette steps (green-700 / yellow-700 /
|
||||
# gray-700) rather than `text-success` / `text-warning` / `text-secondary`
|
||||
# tokens because the functional tokens drop below WCAG 1.4.3 4.5:1 on tinted
|
||||
# surfaces in light mode (~2.88:1 / 3.0:1 / 4.16:1). Local override only;
|
||||
# revert once we-promise/sure#1736 lands token-level fixes.
|
||||
# Text colors here intentionally use palette steps (green/yellow/gray-700)
|
||||
# instead of the `text-success` / `text-warning` / `text-secondary` tokens
|
||||
# because the functional tokens drop below WCAG 1.4.3 4.5:1 on tinted
|
||||
# surfaces in light mode (~2.88:1 / 3.0:1 / 4.16:1). Each variant carries
|
||||
# a theme-dark: override so the dark-700 text doesn't disappear against
|
||||
# the dark-mode tinted surface. Local override only; revert once
|
||||
# we-promise/sure#1736 lands token-level fixes.
|
||||
VARIANTS = {
|
||||
on_track: { classes: "bg-green-500/10 text-green-700", icon: "circle-check" },
|
||||
behind: { classes: "bg-yellow-500/10 text-yellow-700", icon: "triangle-alert" },
|
||||
reached: { classes: "bg-green-500/10 text-green-700", icon: "star" },
|
||||
no_target_date: { classes: "bg-surface-inset text-gray-700", icon: "infinity" },
|
||||
paused: { classes: "bg-surface-inset text-gray-700", icon: "pause" },
|
||||
archived: { classes: "bg-surface-inset text-gray-700", icon: "archive" }
|
||||
on_track: { classes: "bg-green-500/10 text-green-700 theme-dark:text-green-300", icon: "circle-check" },
|
||||
behind: { classes: "bg-yellow-500/10 text-yellow-700 theme-dark:text-yellow-300", icon: "triangle-alert" },
|
||||
reached: { classes: "bg-green-500/10 text-green-700 theme-dark:text-green-300", icon: "star" },
|
||||
no_target_date: { classes: "bg-surface-inset text-gray-700 theme-dark:text-gray-200", icon: "infinity" },
|
||||
paused: { classes: "bg-surface-inset text-gray-700 theme-dark:text-gray-200", icon: "pause" },
|
||||
archived: { classes: "bg-surface-inset text-gray-700 theme-dark:text-gray-200", icon: "archive" }
|
||||
}.freeze
|
||||
|
||||
def initialize(goal:)
|
||||
|
||||
16
app/views/goals/_color_picker.html.erb
Normal file
16
app/views/goals/_color_picker.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<%# locals: (form:, colors:) %>
|
||||
<details class="relative">
|
||||
<summary class="flex items-center gap-2 cursor-pointer text-sm text-secondary list-none">
|
||||
<span class="block w-5 h-5 rounded-full" style="background-color: <%= form.object.color %>"></span>
|
||||
<span><%= t("goals.form_stepper.step1.fields.color") %></span>
|
||||
<%= icon("chevron-down", size: "sm") %>
|
||||
</summary>
|
||||
<div class="absolute z-10 mt-2 p-3 bg-container border border-alpha-black-25 rounded-xl shadow-border-xs flex flex-wrap gap-2 w-fit">
|
||||
<% colors.each do |c| %>
|
||||
<label class="relative">
|
||||
<%= form.radio_button :color, c, class: "sr-only peer" %>
|
||||
<span class="block w-6 h-6 rounded-full cursor-pointer peer-checked:ring-2 peer-checked:ring-offset-2 peer-checked:ring-alpha-black-300" style="background-color: <%= c %>"></span>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
</details>
|
||||
@@ -50,18 +50,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="block text-sm text-secondary mb-2"><%= t("goals.form_stepper.step1.fields.color") %></span>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<% Goal::COLORS.each do |c| %>
|
||||
<label class="relative">
|
||||
<%= f.radio_button :color, c, class: "sr-only peer" %>
|
||||
<div class="w-6 h-6 rounded-full cursor-pointer peer-checked:ring-2 peer-checked:ring-offset-2 peer-checked:ring-gray-500"
|
||||
style="background-color: <%= c %>"></div>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "color_picker", form: f, colors: Goal::COLORS %>
|
||||
|
||||
<%= f.text_area :notes,
|
||||
label: t("goals.form_stepper.step1.fields.notes"),
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
placeholder: t("goals.form_stepper.step1.fields.notes_placeholder") %>
|
||||
<% end %>
|
||||
|
||||
<%= f.hidden_field :color %>
|
||||
<%= render "color_picker", form: f, colors: Goal::COLORS %>
|
||||
</section>
|
||||
|
||||
<section data-goal-stepper-target="step2Panel" class="space-y-5 hidden">
|
||||
@@ -155,7 +155,7 @@
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<div class="flex items-center justify-between pt-2">
|
||||
<div class="flex items-center pt-2">
|
||||
<div class="hidden" data-goal-stepper-target="footerLeftButton">
|
||||
<%= render DS::Button.new(
|
||||
variant: "ghost",
|
||||
@@ -167,16 +167,18 @@
|
||||
}
|
||||
) %>
|
||||
</div>
|
||||
<%= render DS::Button.new(
|
||||
text: t("goals.form_stepper.continue"),
|
||||
variant: "primary",
|
||||
icon: "arrow-right",
|
||||
icon_position: :right,
|
||||
data: {
|
||||
goal_stepper_target: "footerRightButton",
|
||||
action: "click->goal-stepper#footerRight"
|
||||
}
|
||||
) %>
|
||||
<div class="ml-auto">
|
||||
<%= render DS::Button.new(
|
||||
text: t("goals.form_stepper.continue"),
|
||||
variant: "primary",
|
||||
icon: "arrow-right",
|
||||
icon_position: :right,
|
||||
data: {
|
||||
goal_stepper_target: "footerRightButton",
|
||||
action: "click->goal-stepper#footerRight"
|
||||
}
|
||||
) %>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="sr-only"
|
||||
tabindex="-1"
|
||||
|
||||
@@ -137,12 +137,12 @@
|
||||
<% catch_up_money = Money.new(@goal.monthly_target_amount, @goal.currency) %>
|
||||
<% catch_up_delta = @goal.monthly_target_amount.to_d - @stats[:avg_monthly].to_d %>
|
||||
<% catch_up_delta_money = Money.new(catch_up_delta, @goal.currency) %>
|
||||
<%= render DS::Alert.new(variant: "warning", title: t("goals.show.catch_up.title", amount: catch_up_money.format)) do %>
|
||||
<%= render DS::Alert.new(variant: "warning", title: t("goals.show.catch_up.title", delta: catch_up_delta_money.format)) do %>
|
||||
<p class="text-secondary">
|
||||
<% if @goal.target_date %>
|
||||
<%= t("goals.show.catch_up.body_with_date", date: I18n.l(@goal.target_date, format: :long), delta: catch_up_delta_money.format) %>
|
||||
<%= t("goals.show.catch_up.body_with_date", amount: catch_up_money.format, date: I18n.l(@goal.target_date, format: :long)) %>
|
||||
<% else %>
|
||||
<%= t("goals.show.catch_up.body", delta: catch_up_delta_money.format) %>
|
||||
<%= t("goals.show.catch_up.body", amount: catch_up_money.format) %>
|
||||
<% end %>
|
||||
</p>
|
||||
<div class="mt-2">
|
||||
|
||||
@@ -123,9 +123,9 @@ en:
|
||||
on_track: At your current pace, you'll reach this goal around <strong class="text-primary">%{date}</strong>.
|
||||
aria_label: "Projection chart for %{name}"
|
||||
catch_up:
|
||||
title: "Save %{amount}/mo to catch up"
|
||||
body_with_date: "Bump your monthly contribution to stay on track for %{date}. Currently %{delta}/mo behind."
|
||||
body: "Bump your monthly contribution to stay on track. Currently %{delta}/mo behind."
|
||||
title: "Behind by %{delta}/mo"
|
||||
body_with_date: "Save %{amount}/mo to stay on track for %{date}."
|
||||
body: "Save %{amount}/mo to stay on track."
|
||||
cta: "Add %{amount}"
|
||||
confirm_complete_title: Mark this goal complete?
|
||||
confirm_complete_body: It leaves the Ongoing list. You can still archive or restore it later.
|
||||
|
||||
Reference in New Issue
Block a user