diff --git a/.changeset/fn-070-mobile-navigation.md b/.changeset/fn-070-mobile-navigation.md
new file mode 100644
index 0000000000..9339d7a682
--- /dev/null
+++ b/.changeset/fn-070-mobile-navigation.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": minor
+---
+
+summary: Make mobile task creation and Board/List navigation available from every project view.
+category: feature
+dev: Moves the mobile full-task trigger to Header while preserving Planning quick entry.
diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md
index c77458bc7d..b84f356ab9 100644
--- a/docs/dashboard-guide.md
+++ b/docs/dashboard-guide.md
@@ -198,7 +198,7 @@ While the sidebar is active on desktop/tablet project screens, Board and List wo
The active nav-item highlight and the resize-handle hover/focus accent track the active color theme's `--accent` token across all themes, so shadcn, forest, ocean, and other themes no longer show a fixed blue selected state. The Header retains the Fusion brand and project selector, keeps non-navigation controls, and hides duplicate desktop view-toggle entries while the sidebar is active.
-On mobile viewports (`<=768px`), the sidebar is not rendered even when the default-on setting is enabled. The existing bottom `MobileNavBar` remains the navigation surface on project task screens, with mobile-only More-sheet entries for compact tools such as Git Manager, Terminal, Files, and **Import from GitHub**.
+On mobile viewports (`<=768px`), the sidebar is not rendered even when the default-on setting is enabled. The Header's **New Task** action opens the existing full form from any active project view. The bottom `MobileNavBar` provides separate **Tasks** (Board) and **List** destinations, while the Planning column keeps its inline quick-entry composer. Mobile-only More-sheet entries remain available for compact tools such as Git Manager, Terminal, Files, and **Import from GitHub**.
diff --git a/packages/dashboard/app/App.tsx b/packages/dashboard/app/App.tsx
index efb4aef2e3..4538bb43c5 100644
--- a/packages/dashboard/app/App.tsx
+++ b/packages/dashboard/app/App.tsx
@@ -1913,6 +1913,7 @@ function AppInner() {
filesOpen={modalManager.filesOpen}
view={taskView}
onChangeView={viewMode === "project" && currentProject ? handleTaskViewChange : undefined}
+ onNewTask={viewMode === "project" && currentProject ? openNewTaskWithNav : undefined}
showSkillsTab={skillsEnabled}
showAgentsTab={agentsEnabled}
searchQuery={searchQuery}
diff --git a/packages/dashboard/app/__tests__/mobile-feature-access-regression.test.tsx b/packages/dashboard/app/__tests__/mobile-feature-access-regression.test.tsx
index 0873c4f33c..9642065cbe 100644
--- a/packages/dashboard/app/__tests__/mobile-feature-access-regression.test.tsx
+++ b/packages/dashboard/app/__tests__/mobile-feature-access-regression.test.tsx
@@ -133,26 +133,29 @@ describe("Mobile Feature Access Regression Guard", () => {
document.documentElement.style.removeProperty("--mobile-nav-height");
});
- it("list view is accessible via mobile nav bar", () => {
+ it("list view is independently accessible via mobile nav bar", () => {
const props = createDefaultMobileNavProps();
render();
- const tasksTab = screen.getByTestId("mobile-nav-tab-tasks");
- expect(tasksTab.textContent).toContain("Tasks");
-
- fireEvent.click(tasksTab);
- expect(props.onChangeView).toHaveBeenCalledWith("board");
+ fireEvent.click(screen.getByTestId("mobile-nav-tab-list"));
+ expect(props.onChangeView).toHaveBeenCalledWith("list");
});
- it("board view is accessible via mobile nav bar", () => {
+ it("board view is accessible from Tasks on mobile nav bar", () => {
const props = createDefaultMobileNavProps();
render();
- const tasksTab = screen.getByTestId("mobile-nav-tab-tasks");
- expect(tasksTab.textContent).toContain("Tasks");
+ fireEvent.click(screen.getByTestId("mobile-nav-tab-tasks"));
+ expect(props.onChangeView).toHaveBeenCalledWith("board");
+ });
- fireEvent.click(tasksTab);
- expect(props.onChangeView).toHaveBeenCalledWith("list");
+ it("mobile Header exposes New Task without the retired view toggle", () => {
+ const onNewTask = vi.fn();
+ render();
+
+ expect(screen.queryByTestId("mobile-view-toggle")).toBeNull();
+ fireEvent.click(screen.getByTestId("mobile-header-new-task"));
+ expect(onNewTask).toHaveBeenCalledOnce();
});
it("agents view is accessible via mobile nav bar", () => {
diff --git a/packages/dashboard/app/components/Board.tsx b/packages/dashboard/app/components/Board.tsx
index 7b12a9141e..6570649dae 100644
--- a/packages/dashboard/app/components/Board.tsx
+++ b/packages/dashboard/app/components/Board.tsx
@@ -226,6 +226,11 @@ export function Board({ tasks, projectId, maxConcurrent, showWorktreeGrouping, o
setBoardElement((current) => current === element ? current : element);
}, []);
const viewportMode = useViewportMode();
+ /*
+ FNXC:MobileTaskNavigation 2026-08-20-05:47:
+ Issue #2226 moves only the mobile full-task modal trigger to Header. Keep intake quick-create props on every viewport so Planning remains an inline composer.
+ */
+ const mobileFullTaskModalHidden = viewportMode === "mobile";
useColumnScrollSnap(boardElement, { mobileOnly: true });
/*
FNXC:BoardNavigation 2026-08-20-04:47:
@@ -1006,7 +1011,7 @@ export function Board({ tasks, projectId, maxConcurrent, showWorktreeGrouping, o
mergeStrategy={mergeStrategy}
// FNXC:PlanApproval 2026-07-07-00:00: FN-7653 — the plan auto-approve shortcut belongs only to the intake/planning column, never to hold (Todo-like) columns; the built-in Coding workflow's Todo column carries the hold trait and was wrongly receiving this prop pair.
{...((columnDef.flags.intake && !columnDef.flags.archived && !columnDef.flags.complete && !columnDef.flags.countsTowardWip && !columnDef.flags.mergeBlocker && !columnDef.flags.humanReview) ? { planAutoApproveEnabled, onTogglePlanAutoApprove } : {})}
- {...(isCreateColumn && aggregateQuickCreateTarget ? { workflowId: aggregateQuickCreateTarget.workflowId, workflowOptions, defaultWorkflowId: boardWorkflows?.defaultWorkflowId ?? null, onQuickCreate: handleAggregateWorkflowQuickCreate, onNewTask: handleAggregateWorkflowNewTask, onSubtaskBreakdown } : {})}
+ {...(isCreateColumn && aggregateQuickCreateTarget ? { workflowId: aggregateQuickCreateTarget.workflowId, workflowOptions, defaultWorkflowId: boardWorkflows?.defaultWorkflowId ?? null, onQuickCreate: handleAggregateWorkflowQuickCreate, ...(!mobileFullTaskModalHidden ? { onNewTask: handleAggregateWorkflowNewTask } : {}), onSubtaskBreakdown } : {})}
{...(columnDef.flags.mergeBlocker || columnDef.flags.humanReview ? { onToggleAutoMerge: handleToggleAutoMerge } : {})}
{...(columnDefOffersArchiveAllDone(columnDef) ? { onArchiveAllDone } : {})}
{...(laneSortModeChange ? { sortMode: laneSortMode, onSortModeChange: laneSortModeChange } : {})}
@@ -1101,7 +1106,7 @@ export function Board({ tasks, projectId, maxConcurrent, showWorktreeGrouping, o
mergeStrategy={mergeStrategy}
// FNXC:PlanApproval 2026-07-07-00:00: FN-7653 — the plan auto-approve shortcut belongs only to the intake/planning column, never to hold (Todo-like) columns; the built-in Coding workflow's Todo column carries the hold trait and was wrongly receiving this prop pair.
{...((columnDef.flags.intake && !columnDef.flags.archived && !columnDef.flags.complete && !columnDef.flags.countsTowardWip && !columnDef.flags.mergeBlocker && !columnDef.flags.humanReview) ? { planAutoApproveEnabled, onTogglePlanAutoApprove } : {})}
- {...(isCreateColumn ? { workflowOptions, defaultWorkflowId: selectedWorkflow.id, onQuickCreate: handleWorkflowQuickCreate, onNewTask: handleSelectedWorkflowNewTask, onSubtaskBreakdown } : {})}
+ {...(isCreateColumn ? { workflowOptions, defaultWorkflowId: selectedWorkflow.id, onQuickCreate: handleWorkflowQuickCreate, ...(!mobileFullTaskModalHidden ? { onNewTask: handleSelectedWorkflowNewTask } : {}), onSubtaskBreakdown } : {})}
{...(columnDef.flags.mergeBlocker || columnDef.flags.humanReview ? { onToggleAutoMerge: handleToggleAutoMerge } : {})}
{...(columnDefOffersArchiveAllDone(columnDef) ? { onArchiveAllDone } : {})}
{...{ sortMode: laneSortMode, onSortModeChange: laneSortModeChange, doneSortMode: laneSortMode, onDoneSortModeChange: laneSortModeChange }}
diff --git a/packages/dashboard/app/components/Header.tsx b/packages/dashboard/app/components/Header.tsx
index 6457c32023..a901466a86 100644
--- a/packages/dashboard/app/components/Header.tsx
+++ b/packages/dashboard/app/components/Header.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect, useRef, useCallback, useMemo, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
-import { Settings, LayoutGrid, List, Search, X, Activity, MoreHorizontal, Clock, Folder, History, GitBranch, Monitor, Workflow, Bot, Target, Grid3X3, Mail, MessageSquare, Check, Zap, Sparkles, FileText, Brain, Lock, Gauge, Lightbulb, ChevronDown, ChevronRight, PanelRight, Star } from "lucide-react";
+import { Settings, LayoutGrid, List, Search, X, Activity, MoreHorizontal, Clock, Folder, History, GitBranch, Monitor, Workflow, Bot, Target, Grid3X3, Mail, MessageSquare, Check, Zap, Sparkles, FileText, Brain, Lock, Gauge, Lightbulb, ChevronDown, ChevronRight, PanelRight, Plus, Star } from "lucide-react";
import "./Header.css";
// ProjectSelector styles used by the imported standalone component.
import "./ProjectSelector.css";
@@ -74,6 +74,8 @@ export interface HeaderProps {
filesOpen?: boolean;
view?: TaskView;
onChangeView?: (view: TaskView) => void;
+ /** Opens the existing App-owned full New Task modal. */
+ onNewTask?: () => void;
/** Whether to show the skills tab in the view toggle */
showSkillsTab?: boolean;
/** When true, shows the Agents view tab button. Hidden by default (experimental feature). */
@@ -137,6 +139,7 @@ export function Header({
onOpenFiles,
view = "board",
onChangeView,
+ onNewTask,
showSkillsTab,
showAgentsTab,
searchQuery = "",
@@ -621,30 +624,20 @@ export function Header({
{shellConnectionControl}
- {/* Mobile View Toggle - compact board/list switcher in header when mobile nav is active */}
- {hideFullNav && onChangeView && (view === "board" || view === "list") && (
-
-
-
-
+ {/*
+ FNXC:MobileTaskNavigation 2026-08-20-05:47:
+ Issue #2226 moves mobile Board/List navigation to the footer so Header can expose App's single full-task modal entry point from every active project view. The Planning column keeps its separate quick-entry composer.
+ */}
+ {isMobile && mobileNavEnabled && projectId && onNewTask && (
+
)}
{/* Mobile Search Trigger - only on mobile, show trigger button in header */}
diff --git a/packages/dashboard/app/components/ListView.tsx b/packages/dashboard/app/components/ListView.tsx
index a80b8cda00..baf3f2acdf 100644
--- a/packages/dashboard/app/components/ListView.tsx
+++ b/packages/dashboard/app/components/ListView.tsx
@@ -2710,7 +2710,7 @@ export function ListView({
{t("listView.viewOptions", "View")}
- {onNewTask ? (
+ {onNewTask && !isMobile ? (