diff --git a/apps/frontend/src/renderer/components/KanbanBoard.tsx b/apps/frontend/src/renderer/components/KanbanBoard.tsx index 3912d244..784aeb34 100644 --- a/apps/frontend/src/renderer/components/KanbanBoard.tsx +++ b/apps/frontend/src/renderer/components/KanbanBoard.tsx @@ -31,7 +31,7 @@ import { TASK_STATUS_COLUMNS, TASK_STATUS_LABELS } from '../../shared/constants' import { cn } from '../lib/utils'; import { persistTaskStatus, forceCompleteTask, archiveTasks, deleteTasks, useTaskStore } from '../stores/task-store'; import { updateProjectSettings, useProjectStore } from '../stores/project-store'; -import { useKanbanSettingsStore, COLLAPSED_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTH, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH } from '../stores/kanban-settings-store'; +import { useKanbanSettingsStore, DEFAULT_COLUMN_WIDTH, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH, COLLAPSED_COLUMN_WIDTH_REM, MIN_COLUMN_WIDTH_REM, MAX_COLUMN_WIDTH_REM, BASE_FONT_SIZE, pxToRem } from '../stores/kanban-settings-store'; import { useToast } from '../hooks/use-toast'; import { WorktreeCleanupDialog } from './WorktreeCleanupDialog'; import { BulkPRDialog } from './BulkPRDialog'; @@ -338,7 +338,7 @@ const DroppableColumn = memo(function DroppableColumn({ status, tasks, onTaskCli 'border-t-2', isOver && 'drop-zone-highlight' )} - style={{ width: COLLAPSED_COLUMN_WIDTH, minWidth: COLLAPSED_COLUMN_WIDTH, maxWidth: COLLAPSED_COLUMN_WIDTH }} + style={{ width: COLLAPSED_COLUMN_WIDTH_REM, minWidth: COLLAPSED_COLUMN_WIDTH_REM, maxWidth: COLLAPSED_COLUMN_WIDTH_REM }} > {/* Expand button at top */}
@@ -381,7 +381,7 @@ const DroppableColumn = memo(function DroppableColumn({ status, tasks, onTaskCli return (
{ if (!resizingColumn) return; - const deltaX = clientX - resizeStartX.current; + const scaleFactor = parseFloat(getComputedStyle(document.documentElement).fontSize) / BASE_FONT_SIZE; + const deltaX = (clientX - resizeStartX.current) / scaleFactor; const newWidth = Math.max(MIN_COLUMN_WIDTH, Math.min(MAX_COLUMN_WIDTH, resizeStartWidth.current + deltaX)); setColumnWidth(resizingColumn, newWidth); }, [resizingColumn, setColumnWidth]); diff --git a/apps/frontend/src/renderer/stores/kanban-settings-store.ts b/apps/frontend/src/renderer/stores/kanban-settings-store.ts index 85a5e95f..1e6795ba 100644 --- a/apps/frontend/src/renderer/stores/kanban-settings-store.ts +++ b/apps/frontend/src/renderer/stores/kanban-settings-store.ts @@ -52,6 +52,9 @@ interface KanbanSettingsState { /** localStorage key prefix for kanban settings persistence (sync cache) */ const KANBAN_SETTINGS_KEY_PREFIX = 'kanban-column-prefs'; +/** Base font size in pixels for rem conversion (matches CSS default) */ +export const BASE_FONT_SIZE = 16; + /** Default column width in pixels */ export const DEFAULT_COLUMN_WIDTH = 320; @@ -64,6 +67,33 @@ export const MAX_COLUMN_WIDTH = 600; /** Collapsed column width in pixels */ export const COLLAPSED_COLUMN_WIDTH = 48; +// ============================================ +// Rem Conversion Helpers +// ============================================ + +/** + * Convert a pixel value to a rem string. + * Used for CSS width values that should scale with the UI scale system. + * + * @param px - The pixel value to convert + * @returns A rem string (e.g., "20rem" for 320px) + */ +export function pxToRem(px: number): string { + return `${px / BASE_FONT_SIZE}rem`; +} + +/** Default column width in rem (scales with UI) */ +export const DEFAULT_COLUMN_WIDTH_REM = pxToRem(DEFAULT_COLUMN_WIDTH); + +/** Minimum column width in rem (scales with UI) */ +export const MIN_COLUMN_WIDTH_REM = pxToRem(MIN_COLUMN_WIDTH); + +/** Maximum column width in rem (scales with UI) */ +export const MAX_COLUMN_WIDTH_REM = pxToRem(MAX_COLUMN_WIDTH); + +/** Collapsed column width in rem (scales with UI) */ +export const COLLAPSED_COLUMN_WIDTH_REM = pxToRem(COLLAPSED_COLUMN_WIDTH); + // ============================================ // Debounce timer for saving kanban preferences to main process // ============================================