mirror of
https://github.com/we-promise/sure.git
synced 2026-06-01 00:39:01 +00:00
feat(savings_goals/new): live previewable name avatar + ghost cancel + circular header icon
Replace the big square DS::FilledIcon next to the name input with a small Savings::GoalAvatarComponent that previews the goal's avatar (seeded color + first character of the typed name, updates live via new stepper#nameChanged action). Switch the modal header's target avatar from FilledIcon(size: lg, rounded: false) → (size: md, rounded: true) — matches the goal-avatar shape used elsewhere on the page. Replace the hand-rolled <button> for Cancel/Back with DS::Button variant: "ghost". Stepper now drills into the button's inner span to swap the label, same pattern already used for the Continue/Create button on the right. Drop the now-unused footerLeftLabel target.
This commit is contained in:
@@ -15,6 +15,9 @@ export default class extends Controller {
|
||||
"step2Circle",
|
||||
"stepperLine",
|
||||
"modalSubtitle",
|
||||
"nameInput",
|
||||
"amountInput",
|
||||
"avatarPreview",
|
||||
"linkedAccountCheckbox",
|
||||
"initialContributionAmount",
|
||||
"initialContributionAccountSelect",
|
||||
@@ -23,7 +26,6 @@ export default class extends Controller {
|
||||
"reviewAccounts",
|
||||
"reviewSuggested",
|
||||
"footerLeftButton",
|
||||
"footerLeftLabel",
|
||||
"footerRightButton",
|
||||
"submitButton",
|
||||
];
|
||||
@@ -91,6 +93,14 @@ export default class extends Controller {
|
||||
this.updateReview();
|
||||
}
|
||||
|
||||
nameChanged() {
|
||||
if (!this.hasAvatarPreviewTarget || !this.hasNameInputTarget) return;
|
||||
const name = this.nameInputTarget.value.trim();
|
||||
const initial = name ? name.charAt(0).toUpperCase() : "?";
|
||||
const inner = this.avatarPreviewTarget.querySelector('[data-testid="savings-goal-avatar"]');
|
||||
if (inner) inner.textContent = initial;
|
||||
}
|
||||
|
||||
validateStep1() {
|
||||
const requiredInputs = this.step1PanelTarget.querySelectorAll(
|
||||
'input[name="savings_goal[name]"], input[name="savings_goal[target_amount]"]'
|
||||
@@ -163,9 +173,12 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
updateFooter() {
|
||||
if (this.hasFooterLeftLabelTarget) {
|
||||
this.footerLeftLabelTarget.textContent =
|
||||
this.currentStep === 1 ? this.cancelLabelValue : this.backLabelValue;
|
||||
if (this.hasFooterLeftButtonTarget) {
|
||||
const labelSpan = this.footerLeftButtonTarget.querySelector("span");
|
||||
if (labelSpan) {
|
||||
labelSpan.textContent =
|
||||
this.currentStep === 1 ? this.cancelLabelValue : this.backLabelValue;
|
||||
}
|
||||
}
|
||||
if (this.hasFooterRightButtonTarget) {
|
||||
const labelSpan = this.footerRightButtonTarget.querySelector("span");
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-primary mb-2"><%= t("savings_goals.form_stepper.step1.fields.name") %></label>
|
||||
<div class="flex items-stretch gap-2">
|
||||
<span class="shrink-0">
|
||||
<%= render DS::FilledIcon.new(variant: :container, icon: "target", size: "lg", rounded: false) %>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="shrink-0" data-savings-goal-stepper-target="avatarPreview">
|
||||
<%= render Savings::GoalAvatarComponent.new(name: savings_goal.name, color: savings_goal.color, size: "md") %>
|
||||
</span>
|
||||
<%= f.text_field :name,
|
||||
placeholder: t("savings_goals.form_stepper.step1.fields.name_placeholder"),
|
||||
@@ -160,13 +160,14 @@
|
||||
</section>
|
||||
|
||||
<div class="flex items-center justify-between pt-2">
|
||||
<button type="button"
|
||||
class="text-sm font-medium text-secondary hover:text-primary px-2 py-2"
|
||||
data-savings-goal-stepper-target="footerLeftButton"
|
||||
data-action="click->savings-goal-stepper#footerLeft"
|
||||
data-cancel-action="DS--dialog#close">
|
||||
<span data-savings-goal-stepper-target="footerLeftLabel"><%= t("savings_goals.form_stepper.cancel") %></span>
|
||||
</button>
|
||||
<%= render DS::Button.new(
|
||||
variant: "ghost",
|
||||
text: t("savings_goals.form_stepper.cancel"),
|
||||
data: {
|
||||
savings_goal_stepper_target: "footerLeftButton",
|
||||
action: "click->savings-goal-stepper#footerLeft"
|
||||
}
|
||||
) %>
|
||||
<%= render DS::Button.new(
|
||||
text: t("savings_goals.form_stepper.continue"),
|
||||
variant: "primary",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<% dialog.with_header(custom_header: true) do %>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<%= render DS::FilledIcon.new(variant: :container, icon: "target", size: "lg", rounded: false) %>
|
||||
<%= render DS::FilledIcon.new(variant: :container, icon: "target", size: "md", rounded: true) %>
|
||||
<div>
|
||||
<h2 class="text-base font-medium text-primary"><%= t(".heading") %></h2>
|
||||
<p class="text-sm text-secondary mt-0.5" data-savings-goal-stepper-modal-subtitle>
|
||||
|
||||
Reference in New Issue
Block a user