From 39887f5c87036ad27ccccb9e396d0ea4f760deb9 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 17 Jul 2026 00:23:19 -0700 Subject: [PATCH] FN-8186: refine mobile Quick Add action sizing Refine mobile Quick Add controls so every action glyph is readable without compromising compact layout. - Size option and primary action glyphs consistently with spacing tokens. - Tighten mobile control padding while preserving touch-target and desktop behavior. - Extend CSS contract coverage and add a patch changeset. Files changed: .changeset/fn-8186-quick-add-mobile-icon-sizing.md | 7 +++++ .../quick-entry-action-row-height-parity.test.tsx | 35 ++++++++++++++-------- .../dashboard/app/components/QuickEntryBox.css | 31 +++++++++++-------- 3 files changed, 48 insertions(+), 25 deletions(-) Fusion-Task-Id: FN-8186 Fusion-Task-Lineage: 9433521c-6c06-4f89-a486-b8073f2a2961 Co-authored-by: Fusion (runfusion.ai) --- .../fn-8186-quick-add-mobile-icon-sizing.md | 7 ++++ ...ck-entry-action-row-height-parity.test.tsx | 35 ++++++++++++------- .../app/components/QuickEntryBox.css | 31 +++++++++------- 3 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 .changeset/fn-8186-quick-add-mobile-icon-sizing.md diff --git a/.changeset/fn-8186-quick-add-mobile-icon-sizing.md b/.changeset/fn-8186-quick-add-mobile-icon-sizing.md new file mode 100644 index 0000000000..bd7a1b5989 --- /dev/null +++ b/.changeset/fn-8186-quick-add-mobile-icon-sizing.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Quick Add action buttons read at a proper size on mobile. +category: fix +dev: Refines FN-8164 — enlarges the mobile-only (@media max-width:768px) tokenized glyph-size override across the .quick-entry-actions row and tightens horizontal spacing in QuickEntryBox.css; preserves the 36px touch-target floor and leaves desktop rendering unchanged. diff --git a/packages/dashboard/app/__tests__/quick-entry-action-row-height-parity.test.tsx b/packages/dashboard/app/__tests__/quick-entry-action-row-height-parity.test.tsx index 9dba1c6e1e..af5c782e8d 100644 --- a/packages/dashboard/app/__tests__/quick-entry-action-row-height-parity.test.tsx +++ b/packages/dashboard/app/__tests__/quick-entry-action-row-height-parity.test.tsx @@ -205,7 +205,7 @@ describe("quick-entry action row height parity (FN-7680)", () => { expect(mobileBlockMatch![1].trim()).toBe("var(--quick-entry-action-row-height-mobile)"); }); - it("enlarges only mobile icon-forward glyphs with tokenized sizing and tightens horizontal gaps", () => { + it("enlarges every mobile action-row glyph with tokenized sizing and tightens horizontal spacing", () => { const cssContent = loadAllAppCss(); const markerStart = cssContent.indexOf("Quick Entry Mobile Touch + Overflow Fixes"); expect(markerStart).toBeGreaterThan(-1); @@ -215,28 +215,37 @@ describe("quick-entry action row height parity (FN-7680)", () => { expect(sectionEnd).toBeGreaterThan(sectionStart); const mobileSection = cssContent.slice(sectionStart, sectionEnd); - // FNXC:QuickAddActionRow 2026-07-16-15:00: JSDOM cannot resolve CSS vars or + // FNXC:QuickAddActionRow 2026-07-16-16:00: JSDOM cannot resolve CSS vars or // render mocked lucide glyphs, so source-contract assertions prove the - // mobile-only cascade keeps the 36px target while making its small 12/14px - // icon-forward glyphs read proportionately and compactly. + // mobile-only cascade covers both option and primary groups. The broad + // primary-group selector includes the session-advisor glyph rather than + // leaving it at its inline 14px size. const iconRule = mobileSection.match( - /\.quick-entry-primary-group \.btn-icon svg,\s*\n\s*\.quick-entry-primary-group \[data-testid="quick-entry-priority-button"\] svg,\s*\n\s*\.quick-entry-primary-group \[data-testid="quick-entry-fast-toggle"\] svg\s*\{([^}]*)\}/, + /\.quick-entry-options-group svg,\s*\n\s*\.quick-entry-primary-group svg\s*\{([^}]*)\}/, ); expect(iconRule).not.toBeNull(); - expect(iconRule![1]).toMatch(/width:\s*var\(--space-lg\);/); - expect(iconRule![1]).toMatch(/height:\s*var\(--space-lg\);/); + expect(iconRule![1]).toMatch(/width:\s*calc\(var\(--space-md\) \+ var\(--space-sm\)\);/); + expect(iconRule![1]).toMatch(/height:\s*calc\(var\(--space-md\) \+ var\(--space-sm\)\);/); expect(iconRule![1]).not.toMatch(/\d+(?:\.\d+)?px/); - const tokenValue = loadStylesCss().match(/--space-lg:\s*(\d+)px;/); - expect(tokenValue).not.toBeNull(); - expect(Number(tokenValue![1])).toBeGreaterThan(14); + const stylesCss = loadStylesCss(); + const mediumToken = stylesCss.match(/--space-md:\s*(\d+)px;/); + const smallToken = stylesCss.match(/--space-sm:\s*(\d+)px;/); + expect(mediumToken).not.toBeNull(); + expect(smallToken).not.toBeNull(); + expect(Number(mediumToken![1]) + Number(smallToken![1])).toBeGreaterThan(16); const actionGapRule = mobileSection.match(/\.quick-entry-actions\s*\{([^}]*)\}/); const optionGapRule = mobileSection.match(/\.quick-entry-options-group\s*\{([^}]*)\}/); + const compactControlRule = mobileSection.match( + /\.quick-entry-options-group \.btn,\s*\n\s*\.quick-entry-options-group \.wf-optional-steps-dropdown-trigger,\s*\n\s*\.quick-entry-primary-group \.btn-icon\s*\{([^}]*)\}/, + ); expect(actionGapRule?.[1]).toMatch(/column-gap:\s*var\(--space-xs\);/); expect(optionGapRule?.[1]).toMatch(/column-gap:\s*var\(--space-xs\);/); - expect(actionGapRule?.[1]).not.toMatch(/\d+(?:\.\d+)?px/); - expect(optionGapRule?.[1]).not.toMatch(/\d+(?:\.\d+)?px/); + expect(compactControlRule?.[1]).toMatch(/padding-inline:\s*var\(--space-sm\);/); + for (const ruleBody of [actionGapRule?.[1], optionGapRule?.[1], compactControlRule?.[1], iconRule![1]]) { + expect(ruleBody).not.toMatch(/\d+(?:\.\d+)?px/); + } const baseOnlyCss = loadAllAppCssBaseOnly(); const desktopRule = baseOnlyCss.match( @@ -245,7 +254,7 @@ describe("quick-entry action row height parity (FN-7680)", () => { expect(desktopRule).not.toBeNull(); expect(desktopRule![1]).toMatch(/min-height:\s*var\(--quick-entry-action-row-height-desktop\);/); expect(desktopRule![1]).toMatch(/max-height:\s*var\(--quick-entry-action-row-height-desktop\);/); - expect(desktopRule![1]).not.toMatch(/(?:width|height):\s*var\(--space-lg\)/); + expect(desktopRule![1]).not.toMatch(/(?:^|[;\n]\s*)(?:width|height):/); const mobileHeightRule = mobileSection.match( /\.quick-entry-actions \.btn,\s*\n\s*\.quick-entry-actions \.wf-optional-steps-dropdown-trigger\s*\{([^}]*)\}/, diff --git a/packages/dashboard/app/components/QuickEntryBox.css b/packages/dashboard/app/components/QuickEntryBox.css index 1ee6a970f0..ca09d9f303 100644 --- a/packages/dashboard/app/components/QuickEntryBox.css +++ b/packages/dashboard/app/components/QuickEntryBox.css @@ -830,13 +830,15 @@ FN-7682 — the tokenized-CSS test forbids raw px in the workflow-selector rules group `gap`s remain as minimum spacing between controls. */ /* - FNXC:QuickAddActionRow 2026-07-16-15:00: - FN-8164 makes the icon-forward mobile controls read proportionately inside the - FN-7683 36px touch-target box. Scope the --space-lg glyph override to the - primary icon controls so Save, Deps, Models, Node, and Agent retain their - label-friendly inline glyph proportions; their desktop rendering and the - mobile touch-target floor remain intentionally unchanged. Tighten only - horizontal gaps with existing spacing tokens so wrapped rows stay compact. + FNXC:QuickAddActionRow 2026-07-16-16:00: + FN-8186 refines FN-8164 after mobile feedback: every rendered action-row + glyph uses the tokenized 20px composite size, rather than enlarging only + primary icon controls by 2px. Scoping to the two row groups covers option, + text, and icon controls (including the session-advisor toggle) without + changing desktop. Their horizontal padding is tightened locally so the larger + glyphs remain compact and Save keeps its never-clipped content width. The + FN-7683 fixed 36px touch-target height and 32px icon-button width floor stay + intact for accessibility. */ .quick-entry-actions { justify-content: space-between; @@ -855,15 +857,20 @@ FN-7682 — the tokenized-CSS test forbids raw px in the workflow-selector rules margin-left: 0; } + .quick-entry-options-group .btn, + .quick-entry-options-group .wf-optional-steps-dropdown-trigger, + .quick-entry-primary-group .btn-icon { + padding-inline: var(--space-sm); + } + .quick-entry-primary-group .btn-icon { min-width: var(--space-2xl); } - .quick-entry-primary-group .btn-icon svg, - .quick-entry-primary-group [data-testid="quick-entry-priority-button"] svg, - .quick-entry-primary-group [data-testid="quick-entry-fast-toggle"] svg { - width: var(--space-lg); - height: var(--space-lg); + .quick-entry-options-group svg, + .quick-entry-primary-group svg { + width: calc(var(--space-md) + var(--space-sm)); + height: calc(var(--space-md) + var(--space-sm)); } .quick-entry-box .dep-dropdown {