@industry-theme/backlogmd-kanban-panel 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanPanel.d.ts","sourceRoot":"","sources":["../../src/panels/KanbanPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AA2MpD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAMrD,CAAC"}
1
+ {"version":3,"file":"KanbanPanel.d.ts","sourceRoot":"","sources":["../../src/panels/KanbanPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAG9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAyWpD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAMrD,CAAC"}
@@ -12,6 +12,8 @@ interface KanbanColumnProps {
12
12
  /** Callback to load more tasks */
13
13
  onLoadMore?: () => void;
14
14
  onTaskClick?: (task: Task) => void;
15
+ /** Whether column should take full width (for narrow/mobile views) */
16
+ fullWidth?: boolean;
15
17
  }
16
18
  export declare const KanbanColumn: React.FC<KanbanColumnProps>;
17
19
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanColumn.d.ts","sourceRoot":"","sources":["../../../../src/panels/kanban/components/KanbanColumn.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpC;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA8QpD,CAAC"}
1
+ {"version":3,"file":"KanbanColumn.d.ts","sourceRoot":"","sources":["../../../../src/panels/kanban/components/KanbanColumn.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAsRpD,CAAC"}
@@ -9,8 +9,24 @@ export interface ColumnState {
9
9
  }
10
10
  /** Source column names (directory-based) */
11
11
  export type SourceColumn = 'tasks' | 'completed';
12
- /** Display labels for source columns */
12
+ /** Status column names (for 3-column view) */
13
+ export type StatusColumn = 'todo' | 'in-progress' | 'completed';
14
+ /** Display labels for status columns */
15
+ export declare const STATUS_DISPLAY_LABELS: Record<StatusColumn, string>;
16
+ /** Display labels for source columns (legacy) */
13
17
  export declare const SOURCE_DISPLAY_LABELS: Record<SourceColumn, string>;
18
+ /** Status-based column state (computed from source data) */
19
+ export interface StatusColumnState {
20
+ tasks: Task[];
21
+ count: number;
22
+ }
23
+ /** Active tasks pagination state */
24
+ export interface ActiveTasksState {
25
+ total: number;
26
+ loaded: number;
27
+ hasMore: boolean;
28
+ isLoadingMore: boolean;
29
+ }
14
30
  export interface UseKanbanDataResult {
15
31
  tasks: Task[];
16
32
  /** Source columns: "tasks" and "completed" */
@@ -25,6 +41,14 @@ export interface UseKanbanDataResult {
25
41
  loadMore: (source: SourceColumn) => Promise<void>;
26
42
  refreshData: () => Promise<void>;
27
43
  updateTaskStatus: (taskId: string, newStatus: string) => Promise<void>;
44
+ /** Status columns for 3-column view */
45
+ statusColumns: StatusColumn[];
46
+ /** Tasks grouped by status (To Do, In Progress, Completed) */
47
+ tasksByStatus: Map<StatusColumn, StatusColumnState>;
48
+ /** Active tasks (To Do + In Progress) pagination state */
49
+ activeTasksState: ActiveTasksState;
50
+ /** Load more active tasks */
51
+ loadMoreActive: () => Promise<void>;
28
52
  }
29
53
  interface UseKanbanDataOptions {
30
54
  context?: PanelContextValue;
@@ -1 +1 @@
1
- {"version":3,"file":"useKanbanData.d.ts","sourceRoot":"","sources":["../../../../src/panels/kanban/hooks/useKanbanData.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,IAAI,EAAwB,MAAM,kBAAkB,CAAC;AAEzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEtE,kCAAkC;AAClC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;AAEjD,wCAAwC;AACxC,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAG9D,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,8CAA8C;IAC9C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,kCAAkC;IAClC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,mDAAmD;IACnD,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,mBAAmB,CAwVrB"}
1
+ {"version":3,"file":"useKanbanData.d.ts","sourceRoot":"","sources":["../../../../src/panels/kanban/hooks/useKanbanData.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,IAAI,EAAwB,MAAM,kBAAkB,CAAC;AAEzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEtE,kCAAkC;AAClC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;AAEjD,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,WAAW,CAAC;AAEhE,wCAAwC;AACxC,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAI9D,CAAC;AASF,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAG9D,CAAC;AAEF,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,8CAA8C;IAC9C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,kCAAkC;IAClC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,mDAAmD;IACnD,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,uCAAuC;IACvC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,8DAA8D;IAC9D,aAAa,EAAE,GAAG,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IACpD,0DAA0D;IAC1D,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,6BAA6B;IAC7B,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,mBAAmB,CAmYrB"}
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
5
5
  import * as React2 from "react";
6
- import React2__default, { forwardRef, createElement, createContext, useState, useEffect, useContext, useRef, useCallback, useImperativeHandle, useMemo, useLayoutEffect } from "react";
6
+ import React2__default, { forwardRef, createElement, createContext, useState, useEffect, useContext, useRef, useCallback, useLayoutEffect, useImperativeHandle, useMemo } from "react";
7
7
  import { createPortal } from "react-dom";
8
8
  /**
9
9
  * @license lucide-react v0.552.0 - ISC
@@ -1507,9 +1507,10 @@ class PanelFileSystemAdapter {
1507
1507
  return path2.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\/+/g, "/");
1508
1508
  }
1509
1509
  }
1510
- const SOURCE_DISPLAY_LABELS = {
1511
- tasks: "Active",
1512
- completed: "Completed"
1510
+ const STATUS_DISPLAY_LABELS = {
1511
+ "todo": "To Do",
1512
+ "in-progress": "In Progress",
1513
+ "completed": "Completed"
1513
1514
  };
1514
1515
  const DEFAULT_SOURCES = ["tasks", "completed"];
1515
1516
  const DEFAULT_TASKS_LIMIT = 20;
@@ -1768,6 +1769,30 @@ function useKanbanData(options) {
1768
1769
  },
1769
1770
  []
1770
1771
  );
1772
+ const statusColumns = ["todo", "in-progress", "completed"];
1773
+ const tasksByStatus = (() => {
1774
+ const result = /* @__PURE__ */ new Map();
1775
+ const activeTasks = tasksBySource.get("tasks") || [];
1776
+ const completedTasks = tasksBySource.get("completed") || [];
1777
+ const todoTasks = activeTasks.filter((t) => t.status === "To Do");
1778
+ const inProgressTasks = activeTasks.filter((t) => t.status === "In Progress");
1779
+ result.set("todo", { tasks: todoTasks, count: todoTasks.length });
1780
+ result.set("in-progress", { tasks: inProgressTasks, count: inProgressTasks.length });
1781
+ result.set("completed", { tasks: completedTasks, count: completedTasks.length });
1782
+ return result;
1783
+ })();
1784
+ const activeTasksState = (() => {
1785
+ const activeColumnState = columnStates.get("tasks");
1786
+ return {
1787
+ total: (activeColumnState == null ? void 0 : activeColumnState.total) || 0,
1788
+ loaded: (activeColumnState == null ? void 0 : activeColumnState.tasks.length) || 0,
1789
+ hasMore: (activeColumnState == null ? void 0 : activeColumnState.hasMore) || false,
1790
+ isLoadingMore: (activeColumnState == null ? void 0 : activeColumnState.isLoadingMore) || false
1791
+ };
1792
+ })();
1793
+ const loadMoreActive = useCallback(async () => {
1794
+ await loadMore("tasks");
1795
+ }, [loadMore]);
1771
1796
  return {
1772
1797
  tasks,
1773
1798
  sources,
@@ -1778,7 +1803,12 @@ function useKanbanData(options) {
1778
1803
  columnStates,
1779
1804
  loadMore,
1780
1805
  refreshData,
1781
- updateTaskStatus
1806
+ updateTaskStatus,
1807
+ // New 3-column view exports
1808
+ statusColumns,
1809
+ tasksByStatus,
1810
+ activeTasksState,
1811
+ loadMoreActive
1782
1812
  };
1783
1813
  }
1784
1814
  const KanbanColumn = ({
@@ -1788,7 +1818,8 @@ const KanbanColumn = ({
1788
1818
  hasMore = false,
1789
1819
  isLoadingMore = false,
1790
1820
  onLoadMore,
1791
- onTaskClick
1821
+ onTaskClick,
1822
+ fullWidth = false
1792
1823
  }) => {
1793
1824
  const { theme: theme2 } = useTheme();
1794
1825
  const getPriorityColor = (priority) => {
@@ -1810,8 +1841,8 @@ const KanbanColumn = ({
1810
1841
  style: {
1811
1842
  flex: "1 1 0",
1812
1843
  // Grow to fill available width equally
1813
- minWidth: "280px",
1814
- maxWidth: "500px",
1844
+ minWidth: fullWidth ? void 0 : "280px",
1845
+ maxWidth: fullWidth ? void 0 : "500px",
1815
1846
  // Cap max width for readability
1816
1847
  height: "100%",
1817
1848
  // Fill parent height
@@ -1875,7 +1906,11 @@ const KanbanColumn = ({
1875
1906
  flexDirection: "column",
1876
1907
  gap: "8px",
1877
1908
  overflowY: "auto",
1878
- WebkitOverflowScrolling: "touch"
1909
+ overflowX: "hidden",
1910
+ WebkitOverflowScrolling: "touch",
1911
+ // Add padding for scroll content, use margin trick to prevent clipping
1912
+ paddingRight: "4px",
1913
+ marginRight: "-4px"
1879
1914
  },
1880
1915
  children: [
1881
1916
  tasks.map((task) => /* @__PURE__ */ jsxs(
@@ -2054,7 +2089,8 @@ const KanbanColumn = ({
2054
2089
  "Loading..."
2055
2090
  ] }) : `Load more (${remaining} remaining)`
2056
2091
  }
2057
- )
2092
+ ),
2093
+ /* @__PURE__ */ jsx("div", { style: { flexShrink: 0, height: "4px" } })
2058
2094
  ]
2059
2095
  }
2060
2096
  ),
@@ -2324,7 +2360,31 @@ const KanbanPanelContent = ({
2324
2360
  var _a, _b;
2325
2361
  const { theme: theme2 } = useTheme();
2326
2362
  const [_selectedTask, setSelectedTask] = useState(null);
2327
- const { sources, tasksBySource, columnStates, loadMore, error, isBacklogProject, refreshData } = useKanbanData({
2363
+ const [selectedTab, setSelectedTab] = useState("todo");
2364
+ const [isNarrowView, setIsNarrowView] = useState(false);
2365
+ const containerRef = useRef(null);
2366
+ useLayoutEffect(() => {
2367
+ const container = containerRef.current;
2368
+ if (!container) return;
2369
+ const observer = new ResizeObserver((entries) => {
2370
+ for (const entry of entries) {
2371
+ setIsNarrowView(entry.contentRect.width < 768);
2372
+ }
2373
+ });
2374
+ observer.observe(container);
2375
+ return () => observer.disconnect();
2376
+ }, []);
2377
+ const {
2378
+ statusColumns,
2379
+ tasksByStatus,
2380
+ columnStates,
2381
+ loadMore,
2382
+ activeTasksState,
2383
+ loadMoreActive,
2384
+ error,
2385
+ isBacklogProject,
2386
+ refreshData
2387
+ } = useKanbanData({
2328
2388
  context,
2329
2389
  actions,
2330
2390
  tasksLimit: 20,
@@ -2404,6 +2464,7 @@ const KanbanPanelContent = ({
2404
2464
  return /* @__PURE__ */ jsxs(
2405
2465
  "div",
2406
2466
  {
2467
+ ref: containerRef,
2407
2468
  style: {
2408
2469
  padding: "clamp(12px, 3vw, 20px)",
2409
2470
  // Responsive padding for mobile
@@ -2428,22 +2489,72 @@ const KanbanPanelContent = ({
2428
2489
  // Don't shrink header
2429
2490
  display: "flex",
2430
2491
  alignItems: "center",
2492
+ justifyContent: "space-between",
2431
2493
  gap: "12px",
2432
2494
  flexWrap: "wrap"
2433
2495
  },
2434
2496
  children: [
2435
- /* @__PURE__ */ jsx(Kanban, { size: 24, color: theme2.colors.primary }),
2436
- /* @__PURE__ */ jsx(
2437
- "h2",
2438
- {
2439
- style: {
2440
- margin: 0,
2441
- fontSize: theme2.fontSizes[4],
2442
- color: theme2.colors.text
2443
- },
2444
- children: "Kanban Board"
2445
- }
2446
- )
2497
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
2498
+ /* @__PURE__ */ jsx(Kanban, { size: 24, color: theme2.colors.primary }),
2499
+ /* @__PURE__ */ jsx(
2500
+ "h2",
2501
+ {
2502
+ style: {
2503
+ margin: 0,
2504
+ fontSize: theme2.fontSizes[4],
2505
+ color: theme2.colors.text
2506
+ },
2507
+ children: "Kanban Board"
2508
+ }
2509
+ )
2510
+ ] }),
2511
+ isBacklogProject && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "16px", flexWrap: "wrap" }, children: [
2512
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: statusColumns.map((status) => {
2513
+ const statusState = tasksByStatus.get(status);
2514
+ const count = (statusState == null ? void 0 : statusState.count) || 0;
2515
+ const completedState = columnStates.get("completed");
2516
+ const displayCount = status === "completed" && completedState ? `${count}/${completedState.total}` : count;
2517
+ return /* @__PURE__ */ jsxs(
2518
+ "span",
2519
+ {
2520
+ style: {
2521
+ fontSize: theme2.fontSizes[1],
2522
+ color: theme2.colors.textSecondary,
2523
+ background: theme2.colors.backgroundSecondary,
2524
+ padding: "4px 10px",
2525
+ borderRadius: theme2.radii[1],
2526
+ fontWeight: theme2.fontWeights.medium
2527
+ },
2528
+ children: [
2529
+ STATUS_DISPLAY_LABELS[status],
2530
+ ": ",
2531
+ displayCount
2532
+ ]
2533
+ },
2534
+ status
2535
+ );
2536
+ }) }),
2537
+ activeTasksState.hasMore && /* @__PURE__ */ jsx(
2538
+ "button",
2539
+ {
2540
+ onClick: loadMoreActive,
2541
+ disabled: activeTasksState.isLoadingMore,
2542
+ style: {
2543
+ background: theme2.colors.primary,
2544
+ color: theme2.colors.background,
2545
+ border: "none",
2546
+ borderRadius: theme2.radii[2],
2547
+ padding: "6px 12px",
2548
+ fontSize: theme2.fontSizes[1],
2549
+ fontWeight: theme2.fontWeights.medium,
2550
+ cursor: activeTasksState.isLoadingMore ? "wait" : "pointer",
2551
+ opacity: activeTasksState.isLoadingMore ? 0.7 : 1,
2552
+ transition: "opacity 0.2s ease"
2553
+ },
2554
+ children: activeTasksState.isLoadingMore ? "Loading..." : `Load more active (${activeTasksState.total - activeTasksState.loaded} remaining)`
2555
+ }
2556
+ )
2557
+ ] })
2447
2558
  ]
2448
2559
  }
2449
2560
  ),
@@ -2475,42 +2586,103 @@ const KanbanPanelContent = ({
2475
2586
  canInitialize,
2476
2587
  onInitialize: handleInitialize
2477
2588
  }
2478
- ) : /* @__PURE__ */ jsx(
2479
- "div",
2480
- {
2481
- style: {
2482
- flex: 1,
2483
- display: "flex",
2484
- gap: "16px",
2485
- justifyContent: "center",
2486
- // Center columns when they hit max-width
2487
- overflowX: "auto",
2488
- overflowY: "hidden",
2489
- paddingBottom: "8px",
2490
- minHeight: 0,
2491
- // Allow flex child to shrink below content size
2492
- WebkitOverflowScrolling: "touch"
2493
- // Smooth scrolling on iOS
2494
- },
2495
- children: sources.map((source2) => {
2496
- const columnTasks = tasksBySource.get(source2) || [];
2497
- const columnState = columnStates.get(source2);
2498
- return /* @__PURE__ */ jsx(
2499
- KanbanColumn,
2500
- {
2501
- status: SOURCE_DISPLAY_LABELS[source2],
2502
- tasks: columnTasks,
2503
- total: columnState == null ? void 0 : columnState.total,
2504
- hasMore: columnState == null ? void 0 : columnState.hasMore,
2505
- isLoadingMore: columnState == null ? void 0 : columnState.isLoadingMore,
2506
- onLoadMore: () => loadMore(source2),
2507
- onTaskClick: handleTaskClick
2508
- },
2509
- source2
2510
- );
2511
- })
2512
- }
2513
- )
2589
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2590
+ isNarrowView && /* @__PURE__ */ jsx(
2591
+ "div",
2592
+ {
2593
+ style: {
2594
+ flexShrink: 0,
2595
+ display: "flex",
2596
+ gap: "4px",
2597
+ background: theme2.colors.backgroundSecondary,
2598
+ borderRadius: theme2.radii[2],
2599
+ padding: "4px"
2600
+ },
2601
+ children: statusColumns.map((status) => {
2602
+ const isSelected = status === selectedTab;
2603
+ const statusState = tasksByStatus.get(status);
2604
+ const count = (statusState == null ? void 0 : statusState.count) || 0;
2605
+ return /* @__PURE__ */ jsxs(
2606
+ "button",
2607
+ {
2608
+ onClick: () => setSelectedTab(status),
2609
+ style: {
2610
+ flex: 1,
2611
+ padding: "10px 12px",
2612
+ border: "none",
2613
+ borderRadius: theme2.radii[1],
2614
+ background: isSelected ? theme2.colors.primary : "transparent",
2615
+ color: isSelected ? theme2.colors.background : theme2.colors.textSecondary,
2616
+ fontSize: theme2.fontSizes[1],
2617
+ fontWeight: theme2.fontWeights.medium,
2618
+ cursor: "pointer",
2619
+ transition: "all 0.2s ease",
2620
+ display: "flex",
2621
+ alignItems: "center",
2622
+ justifyContent: "center",
2623
+ gap: "6px"
2624
+ },
2625
+ children: [
2626
+ STATUS_DISPLAY_LABELS[status],
2627
+ /* @__PURE__ */ jsx(
2628
+ "span",
2629
+ {
2630
+ style: {
2631
+ background: isSelected ? "rgba(255,255,255,0.2)" : theme2.colors.background,
2632
+ padding: "2px 6px",
2633
+ borderRadius: theme2.radii[1],
2634
+ fontSize: theme2.fontSizes[0]
2635
+ },
2636
+ children: count
2637
+ }
2638
+ )
2639
+ ]
2640
+ },
2641
+ status
2642
+ );
2643
+ })
2644
+ }
2645
+ ),
2646
+ /* @__PURE__ */ jsx(
2647
+ "div",
2648
+ {
2649
+ style: {
2650
+ flex: 1,
2651
+ display: "flex",
2652
+ gap: "16px",
2653
+ justifyContent: "center",
2654
+ // Center columns when they hit max-width
2655
+ overflowX: isNarrowView ? "hidden" : "auto",
2656
+ overflowY: "hidden",
2657
+ paddingBottom: "8px",
2658
+ minHeight: 0,
2659
+ // Allow flex child to shrink below content size
2660
+ WebkitOverflowScrolling: "touch"
2661
+ // Smooth scrolling on iOS
2662
+ },
2663
+ children: statusColumns.filter((status) => !isNarrowView || status === selectedTab).map((status) => {
2664
+ const statusState = tasksByStatus.get(status);
2665
+ const columnTasks = (statusState == null ? void 0 : statusState.tasks) || [];
2666
+ const isCompleted = status === "completed";
2667
+ const completedState = columnStates.get("completed");
2668
+ return /* @__PURE__ */ jsx(
2669
+ KanbanColumn,
2670
+ {
2671
+ status: STATUS_DISPLAY_LABELS[status],
2672
+ tasks: columnTasks,
2673
+ total: isCompleted ? completedState == null ? void 0 : completedState.total : void 0,
2674
+ hasMore: isCompleted ? completedState == null ? void 0 : completedState.hasMore : false,
2675
+ isLoadingMore: isCompleted ? completedState == null ? void 0 : completedState.isLoadingMore : false,
2676
+ onLoadMore: isCompleted ? () => loadMore("completed") : void 0,
2677
+ onTaskClick: handleTaskClick,
2678
+ fullWidth: isNarrowView
2679
+ },
2680
+ status
2681
+ );
2682
+ })
2683
+ }
2684
+ )
2685
+ ] })
2514
2686
  ]
2515
2687
  }
2516
2688
  );