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) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-8186-quick-add-mobile-icon-sizing.md
Normal file
7
.changeset/fn-8186-quick-add-mobile-icon-sizing.md
Normal file
@@ -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.
|
||||||
@@ -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)");
|
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 cssContent = loadAllAppCss();
|
||||||
const markerStart = cssContent.indexOf("Quick Entry Mobile Touch + Overflow Fixes");
|
const markerStart = cssContent.indexOf("Quick Entry Mobile Touch + Overflow Fixes");
|
||||||
expect(markerStart).toBeGreaterThan(-1);
|
expect(markerStart).toBeGreaterThan(-1);
|
||||||
@@ -215,28 +215,37 @@ describe("quick-entry action row height parity (FN-7680)", () => {
|
|||||||
expect(sectionEnd).toBeGreaterThan(sectionStart);
|
expect(sectionEnd).toBeGreaterThan(sectionStart);
|
||||||
const mobileSection = cssContent.slice(sectionStart, sectionEnd);
|
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
|
// render mocked lucide glyphs, so source-contract assertions prove the
|
||||||
// mobile-only cascade keeps the 36px target while making its small 12/14px
|
// mobile-only cascade covers both option and primary groups. The broad
|
||||||
// icon-forward glyphs read proportionately and compactly.
|
// primary-group selector includes the session-advisor glyph rather than
|
||||||
|
// leaving it at its inline 14px size.
|
||||||
const iconRule = mobileSection.match(
|
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).not.toBeNull();
|
||||||
expect(iconRule![1]).toMatch(/width:\s*var\(--space-lg\);/);
|
expect(iconRule![1]).toMatch(/width:\s*calc\(var\(--space-md\) \+ var\(--space-sm\)\);/);
|
||||||
expect(iconRule![1]).toMatch(/height:\s*var\(--space-lg\);/);
|
expect(iconRule![1]).toMatch(/height:\s*calc\(var\(--space-md\) \+ var\(--space-sm\)\);/);
|
||||||
expect(iconRule![1]).not.toMatch(/\d+(?:\.\d+)?px/);
|
expect(iconRule![1]).not.toMatch(/\d+(?:\.\d+)?px/);
|
||||||
|
|
||||||
const tokenValue = loadStylesCss().match(/--space-lg:\s*(\d+)px;/);
|
const stylesCss = loadStylesCss();
|
||||||
expect(tokenValue).not.toBeNull();
|
const mediumToken = stylesCss.match(/--space-md:\s*(\d+)px;/);
|
||||||
expect(Number(tokenValue![1])).toBeGreaterThan(14);
|
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 actionGapRule = mobileSection.match(/\.quick-entry-actions\s*\{([^}]*)\}/);
|
||||||
const optionGapRule = mobileSection.match(/\.quick-entry-options-group\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(actionGapRule?.[1]).toMatch(/column-gap:\s*var\(--space-xs\);/);
|
||||||
expect(optionGapRule?.[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(compactControlRule?.[1]).toMatch(/padding-inline:\s*var\(--space-sm\);/);
|
||||||
expect(optionGapRule?.[1]).not.toMatch(/\d+(?:\.\d+)?px/);
|
for (const ruleBody of [actionGapRule?.[1], optionGapRule?.[1], compactControlRule?.[1], iconRule![1]]) {
|
||||||
|
expect(ruleBody).not.toMatch(/\d+(?:\.\d+)?px/);
|
||||||
|
}
|
||||||
|
|
||||||
const baseOnlyCss = loadAllAppCssBaseOnly();
|
const baseOnlyCss = loadAllAppCssBaseOnly();
|
||||||
const desktopRule = baseOnlyCss.match(
|
const desktopRule = baseOnlyCss.match(
|
||||||
@@ -245,7 +254,7 @@ describe("quick-entry action row height parity (FN-7680)", () => {
|
|||||||
expect(desktopRule).not.toBeNull();
|
expect(desktopRule).not.toBeNull();
|
||||||
expect(desktopRule![1]).toMatch(/min-height:\s*var\(--quick-entry-action-row-height-desktop\);/);
|
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]).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(
|
const mobileHeightRule = mobileSection.match(
|
||||||
/\.quick-entry-actions \.btn,\s*\n\s*\.quick-entry-actions \.wf-optional-steps-dropdown-trigger\s*\{([^}]*)\}/,
|
/\.quick-entry-actions \.btn,\s*\n\s*\.quick-entry-actions \.wf-optional-steps-dropdown-trigger\s*\{([^}]*)\}/,
|
||||||
|
|||||||
@@ -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.
|
group `gap`s remain as minimum spacing between controls.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
FNXC:QuickAddActionRow 2026-07-16-15:00:
|
FNXC:QuickAddActionRow 2026-07-16-16:00:
|
||||||
FN-8164 makes the icon-forward mobile controls read proportionately inside the
|
FN-8186 refines FN-8164 after mobile feedback: every rendered action-row
|
||||||
FN-7683 36px touch-target box. Scope the --space-lg glyph override to the
|
glyph uses the tokenized 20px composite size, rather than enlarging only
|
||||||
primary icon controls so Save, Deps, Models, Node, and Agent retain their
|
primary icon controls by 2px. Scoping to the two row groups covers option,
|
||||||
label-friendly inline glyph proportions; their desktop rendering and the
|
text, and icon controls (including the session-advisor toggle) without
|
||||||
mobile touch-target floor remain intentionally unchanged. Tighten only
|
changing desktop. Their horizontal padding is tightened locally so the larger
|
||||||
horizontal gaps with existing spacing tokens so wrapped rows stay compact.
|
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 {
|
.quick-entry-actions {
|
||||||
justify-content: space-between;
|
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;
|
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 {
|
.quick-entry-primary-group .btn-icon {
|
||||||
min-width: var(--space-2xl);
|
min-width: var(--space-2xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-entry-primary-group .btn-icon svg,
|
.quick-entry-options-group svg,
|
||||||
.quick-entry-primary-group [data-testid="quick-entry-priority-button"] svg,
|
.quick-entry-primary-group svg {
|
||||||
.quick-entry-primary-group [data-testid="quick-entry-fast-toggle"] svg {
|
width: calc(var(--space-md) + var(--space-sm));
|
||||||
width: var(--space-lg);
|
height: calc(var(--space-md) + var(--space-sm));
|
||||||
height: var(--space-lg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-entry-box .dep-dropdown {
|
.quick-entry-box .dep-dropdown {
|
||||||
|
|||||||
Reference in New Issue
Block a user