From 058a041714c6e8fcc08110615025ec944acd0554 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 1 Jul 2026 00:20:56 -0700 Subject: [PATCH] FN-7348: pin mobile planning New session footer Keep the mobile Planning Mode New session CTA reachable while saved sessions scroll independently. - Bound the mobile planning list shell so only the session list scrolls. - Preserve the sidebar footer as a non-shrinking bottom action in list view. - Add CSS contract coverage and a changeset for the published CLI package. Files changed: .changeset/fn-7348-mobile-planning-new-session.md | 7 ++++++ .../dashboard/app/components/PlanningModeModal.css | 23 +++++++++++++++++ .../__tests__/PlanningModeModal.css.test.ts | 29 ++++++++++++++++++++++ 3 files changed, 59 insertions(+) Fusion-Task-Id: FN-7348 Fusion-Task-Lineage: 0142e539-3e4c-4ac5-9a44-d02bce2c139b Co-authored-by: Fusion (runfusion.ai) --- .../fn-7348-mobile-planning-new-session.md | 7 +++++ .../app/components/PlanningModeModal.css | 23 +++++++++++++++ .../__tests__/PlanningModeModal.css.test.ts | 29 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 .changeset/fn-7348-mobile-planning-new-session.md diff --git a/.changeset/fn-7348-mobile-planning-new-session.md b/.changeset/fn-7348-mobile-planning-new-session.md new file mode 100644 index 0000000000..d6fa849a69 --- /dev/null +++ b/.changeset/fn-7348-mobile-planning-new-session.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Keep the mobile Planning Mode New session button pinned at the bottom. +category: fix +dev: Bounds the mobile Planning sessions list so only saved sessions scroll above the footer CTA. diff --git a/packages/dashboard/app/components/PlanningModeModal.css b/packages/dashboard/app/components/PlanningModeModal.css index 9a1213a03e..7f86b2161a 100644 --- a/packages/dashboard/app/components/PlanningModeModal.css +++ b/packages/dashboard/app/components/PlanningModeModal.css @@ -497,6 +497,29 @@ The New session button must look EXACTLY like Missions' primary sidebar create b border-right: none; border-bottom: 1px solid var(--border); } + /* + FNXC:PlanningMode 2026-06-30-00:00: + Mobile list view must keep the New session CTA reachable like Missions' bottom sidebar action. Bound the sidebar to the Planning pane and let only the session list scroll above the fixed footer; detail view still hides the sidebar through the existing show-detail rule. + */ + .planning-modal-body--show-list { + flex: 1; + min-height: 0; + overflow: hidden; + } + .planning-modal-body--show-list .planning-sidebar { + flex: 1 1 auto; + height: 100%; + min-height: 0; + max-height: 100%; + } + .planning-modal-body--show-list .planning-sidebar-list { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + } + .planning-modal-body--show-list .planning-sidebar-footer { + flex-shrink: 0; + } .planning-modal-body--show-detail .planning-sidebar { display: none; } diff --git a/packages/dashboard/app/components/__tests__/PlanningModeModal.css.test.ts b/packages/dashboard/app/components/__tests__/PlanningModeModal.css.test.ts index c78b77f632..8d8f0cd2c5 100644 --- a/packages/dashboard/app/components/__tests__/PlanningModeModal.css.test.ts +++ b/packages/dashboard/app/components/__tests__/PlanningModeModal.css.test.ts @@ -6,6 +6,7 @@ import { getMediaBlocks } from "./PlanningModeModal.test-helpers"; const PLANNING_CSS_PATH = resolve(__dirname, "..", "PlanningModeModal.css"); const TABLET_SUMMARY_ACTIONS_QUERY = "@media (min-width: 769px) and (max-width: 1024px)"; const MOBILE_ACTIONS_QUERY = "@media (max-width: 768px)"; +const MOBILE_PLANNING_SHELL_QUERY = "@media (max-width: 768px), (max-height: 480px)"; function loadPlanningCss(): string { return readFileSync(PLANNING_CSS_PATH, "utf-8"); @@ -67,4 +68,32 @@ describe("PlanningModeModal CSS responsive action contract", () => { expect(embeddedRule).toMatch(/height\s*:\s*100%\s*;/); expect(embeddedRule).toMatch(/max-height\s*:\s*100%\s*;/); }); + + it("keeps the mobile sessions list scrolling above the bottom-pinned New session footer", () => { + const css = loadPlanningCss(); + const mobileShellCss = getMediaBlocks(css, MOBILE_PLANNING_SHELL_QUERY).join("\n"); + + const showListRule = findRule(mobileShellCss, ".planning-modal-body--show-list"); + expect(showListRule).toBeTruthy(); + expect(showListRule).toMatch(/flex\s*:\s*1\s*;/); + expect(showListRule).toMatch(/min-height\s*:\s*0\s*;/); + expect(showListRule).toMatch(/overflow\s*:\s*hidden\s*;/); + + const sidebarRule = findRule(mobileShellCss, ".planning-modal-body--show-list .planning-sidebar"); + expect(sidebarRule).toBeTruthy(); + expect(sidebarRule).toMatch(/flex\s*:\s*1 1 auto\s*;/); + expect(sidebarRule).toMatch(/height\s*:\s*100%\s*;/); + expect(sidebarRule).toMatch(/min-height\s*:\s*0\s*;/); + expect(sidebarRule).toMatch(/max-height\s*:\s*100%\s*;/); + + const sidebarListRule = findRule(mobileShellCss, ".planning-modal-body--show-list .planning-sidebar-list"); + expect(sidebarListRule).toBeTruthy(); + expect(sidebarListRule).toMatch(/flex\s*:\s*1 1 auto\s*;/); + expect(sidebarListRule).toMatch(/min-height\s*:\s*0\s*;/); + expect(sidebarListRule).toMatch(/overflow-y\s*:\s*auto\s*;/); + + const footerRule = findRule(mobileShellCss, ".planning-modal-body--show-list .planning-sidebar-footer"); + expect(footerRule).toBeTruthy(); + expect(footerRule).toMatch(/flex-shrink\s*:\s*0\s*;/); + }); });