diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx
index 1b248e7e8..f96a13ab2 100644
--- a/src/app/(main)/boards/BoardProvider.tsx
+++ b/src/app/(main)/boards/BoardProvider.tsx
@@ -74,9 +74,7 @@ export function BoardProvider({
// Get current layout sizes from BoardBody if registered
const layoutData = layoutGetterRef.current?.();
- console.log('layoutData from getter:', layoutData);
const parameters = layoutData ? { ...board.parameters, ...layoutData } : board.parameters;
- console.log('parameters to save:', parameters);
const result = await mutateAsync({
...board,
diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx
index d9133b8fc..5e2c32264 100644
--- a/src/app/(main)/boards/[boardId]/BoardBody.tsx
+++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx
@@ -1,24 +1,12 @@
-import { Box, Button, Column, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
+import { Button, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
import { produce } from 'immer';
-import { Fragment, type ReactElement, useEffect, useRef } from 'react';
+import { Fragment, useEffect, useRef } from 'react';
import { Group, type GroupImperativeHandle, Panel, Separator } from 'react-resizable-panels';
import { v4 as uuid } from 'uuid';
import { useBoard } from '@/components/hooks';
-import { ChevronDown, Minus, Plus, X } from '@/components/icons';
-import type { BoardColumn as BoardColumnType } from '@/lib/types';
-
-const CATALOG = {
- text: {
- label: 'Text',
- component: BoardColumn,
- },
-};
-
-const MIN_ROW_HEIGHT = 300;
-const MAX_ROW_HEIGHT = 600;
-const MIN_COLUMN_WIDTH = 300;
-const BUTTON_ROW_HEIGHT = 60;
-const MAX_COLUMNS = 4;
+import { Plus } from '@/components/icons';
+import { BoardRow } from './BoardRow';
+import { BUTTON_ROW_HEIGHT, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT } from './boardConstants';
export function BoardBody() {
const { board, editing, updateBoard, saveBoard, isPending, registerLayoutGetter } = useBoard();
@@ -29,19 +17,14 @@ export function BoardBody() {
useEffect(() => {
registerLayoutGetter(() => {
const rows = board?.parameters?.rows;
- console.log('Layout getter called, rows:', rows);
- console.log('rowGroupRef.current:', rowGroupRef.current);
- console.log('columnGroupRefs.current:', columnGroupRefs.current);
if (!rows?.length) return null;
const rowLayout = rowGroupRef.current?.getLayout();
- console.log('rowLayout:', rowLayout);
const updatedRows = rows.map(row => {
const columnGroupRef = columnGroupRefs.current.get(row.id);
const columnLayout = columnGroupRef?.getLayout();
- console.log(`Row ${row.id} columnLayout:`, columnLayout);
const updatedColumns = row.columns.map(col => ({
...col,
@@ -55,7 +38,6 @@ export function BoardBody() {
};
});
- console.log('updatedRows:', updatedRows);
return { rows: updatedRows };
});
}, [registerLayoutGetter, board?.parameters?.rows]);
@@ -68,8 +50,6 @@ export function BoardBody() {
}
};
- console.log({ board });
-
const handleAddRow = () => {
updateBoard({
parameters: produce(board.parameters, draft => {
@@ -168,167 +148,3 @@ export function BoardBody() {
);
}
-
-function BoardRow({
- rowId,
- rowIndex,
- rowCount,
- columns,
- editing = false,
- onRemove,
- onMoveUp,
- onMoveDown,
- onRegisterRef,
-}: {
- rowId: string;
- rowIndex: number;
- rowCount: number;
- columns: BoardColumnType[];
- editing?: boolean;
- onRemove?: (id: string) => void;
- onMoveUp?: (id: string) => void;
- onMoveDown?: (id: string) => void;
- onRegisterRef?: (rowId: string, ref: GroupImperativeHandle | null) => void;
-}) {
- const { board, updateBoard } = useBoard();
-
- const handleGroupRef = (ref: GroupImperativeHandle | null) => {
- onRegisterRef?.(rowId, ref);
- };
-
- const handleAddColumn = () => {
- updateBoard({
- parameters: produce(board.parameters, draft => {
- const rowIndex = draft.rows.findIndex(row => row.id === rowId);
- const row = draft.rows[rowIndex];
-
- if (!row) {
- draft.rows[rowIndex] = { id: uuid(), columns: [] };
- }
- row.columns.push({ id: uuid(), component: null });
- }),
- });
- };
-
- const handleRemoveColumn = (columnId: string) => {
- updateBoard({
- parameters: produce(board.parameters, draft => {
- const row = draft.rows.find(row => row.id === rowId);
- if (row) {
- row.columns = row.columns.filter(col => col.id !== columnId);
- }
- }),
- });
- };
-
- return (
-
- {columns?.map((column, index) => (
-
-
- 1}
- />
-
- {index < columns?.length - 1 && }
-
- ))}
- {editing && (
-
-
-
- Move row up
-
-
-
- Add column
-
-
-
- Remove row
-
-
-
- Move row down
-
-
- )}
-
- );
-}
-
-function BoardColumn({
- id,
- component,
- editing = false,
- onRemove,
- canRemove = true,
-}: {
- id: string;
- component?: ReactElement;
- editing?: boolean;
- onRemove?: (id: string) => void;
- canRemove?: boolean;
-}) {
- const handleAddComponent = () => {};
-
- return (
-
- {editing && canRemove && (
-
-
-
- Remove column
-
-
- )}
- {editing && (
-
- )}
-
- );
-}
diff --git a/src/app/(main)/boards/[boardId]/BoardColumn.tsx b/src/app/(main)/boards/[boardId]/BoardColumn.tsx
new file mode 100644
index 000000000..bfaf22fc9
--- /dev/null
+++ b/src/app/(main)/boards/[boardId]/BoardColumn.tsx
@@ -0,0 +1,52 @@
+import { Box, Button, Column, Icon, Tooltip, TooltipTrigger } from '@umami/react-zen';
+import type { ReactElement } from 'react';
+import { Plus, X } from '@/components/icons';
+
+export function BoardColumn({
+ id,
+ component,
+ editing = false,
+ onRemove,
+ canRemove = true,
+}: {
+ id: string;
+ component?: ReactElement;
+ editing?: boolean;
+ onRemove?: (id: string) => void;
+ canRemove?: boolean;
+}) {
+ const handleAddComponent = () => {};
+
+ return (
+
+ {editing && canRemove && (
+
+
+
+ Remove column
+
+
+ )}
+ {editing && (
+
+ )}
+
+ );
+}
diff --git a/src/app/(main)/boards/[boardId]/BoardEditHeader.tsx b/src/app/(main)/boards/[boardId]/BoardEditHeader.tsx
new file mode 100644
index 000000000..e49449166
--- /dev/null
+++ b/src/app/(main)/boards/[boardId]/BoardEditHeader.tsx
@@ -0,0 +1,99 @@
+import {
+ Button,
+ Column,
+ Grid,
+ Heading,
+ LoadingButton,
+ Row,
+ Text,
+ TextField,
+} from '@umami/react-zen';
+import { useBoard, useMessages, useNavigation } from '@/components/hooks';
+import { WebsiteSelect } from '@/components/input/WebsiteSelect';
+
+export function BoardEditHeader() {
+ const { board, updateBoard, saveBoard, isPending } = useBoard();
+ const { formatMessage, labels } = useMessages();
+ const { router, renderUrl } = useNavigation();
+ const defaultName = formatMessage(labels.untitled);
+
+ const handleNameChange = (value: string) => {
+ updateBoard({ name: value });
+ };
+
+ const handleDescriptionChange = (value: string) => {
+ updateBoard({ description: value });
+ };
+
+ const handleWebsiteChange = (websiteId: string) => {
+ updateBoard({ parameters: { ...board.parameters, websiteId } });
+ };
+
+ const handleSave = async () => {
+ await saveBoard();
+ if (board.id) {
+ router.push(renderUrl(`/boards/${board.id}`));
+ }
+ };
+
+ const handleCancel = () => {
+ if (board.id) {
+ router.push(renderUrl(`/boards/${board.id}`));
+ } else {
+ router.push(renderUrl('/boards'));
+ }
+ };
+
+ return (
+
+
+
+
+ {board?.name}
+
+
+
+
+ {board?.description}
+
+
+
+ {formatMessage(labels.website)}
+
+
+
+
+
+
+
+ {formatMessage(labels.save)}
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/boards/[boardId]/BoardHeader.tsx b/src/app/(main)/boards/[boardId]/BoardHeader.tsx
index 345da086d..ed2e11970 100644
--- a/src/app/(main)/boards/[boardId]/BoardHeader.tsx
+++ b/src/app/(main)/boards/[boardId]/BoardHeader.tsx
@@ -1,19 +1,6 @@
-import {
- Button,
- Column,
- Grid,
- Heading,
- LoadingButton,
- Row,
- Text,
- TextField,
-} from '@umami/react-zen';
-import { IconLabel } from '@/components/common/IconLabel';
-import { LinkButton } from '@/components/common/LinkButton';
-import { PageHeader } from '@/components/common/PageHeader';
-import { useBoard, useMessages, useNavigation, useWebsiteQuery } from '@/components/hooks';
-import { Edit } from '@/components/icons';
-import { WebsiteSelect } from '@/components/input/WebsiteSelect';
+import { useBoard } from '@/components/hooks';
+import { BoardEditHeader } from './BoardEditHeader';
+import { BoardViewHeader } from './BoardViewHeader';
export function BoardHeader() {
const { board, editing } = useBoard();
@@ -24,106 +11,3 @@ export function BoardHeader() {
return ;
}
-
-function BoardViewHeader() {
- const { board } = useBoard();
- const { renderUrl } = useNavigation();
- const { formatMessage, labels } = useMessages();
- const { data: website } = useWebsiteQuery(board?.parameters?.websiteId);
-
- return (
-
- {website?.name && {website.name}}
-
- }>{formatMessage(labels.edit)}
-
-
- );
-}
-
-function BoardEditHeader() {
- const { board, updateBoard, saveBoard, isPending } = useBoard();
- const { formatMessage, labels } = useMessages();
- const { router, renderUrl } = useNavigation();
- const defaultName = formatMessage(labels.untitled);
-
- const handleNameChange = (value: string) => {
- updateBoard({ name: value });
- };
-
- const handleDescriptionChange = (value: string) => {
- updateBoard({ description: value });
- };
-
- const handleWebsiteChange = (websiteId: string) => {
- updateBoard({ parameters: { ...board.parameters, websiteId } });
- };
-
- const handleSave = async () => {
- await saveBoard();
- if (board.id) {
- router.push(renderUrl(`/boards/${board.id}`));
- }
- };
-
- const handleCancel = () => {
- if (board.id) {
- router.push(renderUrl(`/boards/${board.id}`));
- } else {
- router.push(renderUrl('/boards'));
- }
- };
-
- return (
-
-
-
-
- {board?.name}
-
-
-
-
- {board?.description}
-
-
-
- {formatMessage(labels.website)}
-
-
-
-
-
-
-
- {formatMessage(labels.save)}
-
-
-
-
- );
-}
diff --git a/src/app/(main)/boards/[boardId]/BoardRow.tsx b/src/app/(main)/boards/[boardId]/BoardRow.tsx
new file mode 100644
index 000000000..7c5ee47ef
--- /dev/null
+++ b/src/app/(main)/boards/[boardId]/BoardRow.tsx
@@ -0,0 +1,125 @@
+import { Button, Column, Icon, Tooltip, TooltipTrigger } from '@umami/react-zen';
+import { produce } from 'immer';
+import { Fragment } from 'react';
+import { Group, type GroupImperativeHandle, Panel, Separator } from 'react-resizable-panels';
+import { v4 as uuid } from 'uuid';
+import { useBoard } from '@/components/hooks';
+import { ChevronDown, Minus, Plus } from '@/components/icons';
+import type { BoardColumn as BoardColumnType } from '@/lib/types';
+import { BoardColumn } from './BoardColumn';
+import { MAX_COLUMNS, MIN_COLUMN_WIDTH } from './boardConstants';
+
+export function BoardRow({
+ rowId,
+ rowIndex,
+ rowCount,
+ columns,
+ editing = false,
+ onRemove,
+ onMoveUp,
+ onMoveDown,
+ onRegisterRef,
+}: {
+ rowId: string;
+ rowIndex: number;
+ rowCount: number;
+ columns: BoardColumnType[];
+ editing?: boolean;
+ onRemove?: (id: string) => void;
+ onMoveUp?: (id: string) => void;
+ onMoveDown?: (id: string) => void;
+ onRegisterRef?: (rowId: string, ref: GroupImperativeHandle | null) => void;
+}) {
+ const { board, updateBoard } = useBoard();
+
+ const handleGroupRef = (ref: GroupImperativeHandle | null) => {
+ onRegisterRef?.(rowId, ref);
+ };
+
+ const handleAddColumn = () => {
+ updateBoard({
+ parameters: produce(board.parameters, draft => {
+ const rowIndex = draft.rows.findIndex(row => row.id === rowId);
+ const row = draft.rows[rowIndex];
+
+ if (!row) {
+ draft.rows[rowIndex] = { id: uuid(), columns: [] };
+ }
+ row.columns.push({ id: uuid(), component: null });
+ }),
+ });
+ };
+
+ const handleRemoveColumn = (columnId: string) => {
+ updateBoard({
+ parameters: produce(board.parameters, draft => {
+ const row = draft.rows.find(row => row.id === rowId);
+ if (row) {
+ row.columns = row.columns.filter(col => col.id !== columnId);
+ }
+ }),
+ });
+ };
+
+ return (
+
+ {columns?.map((column, index) => (
+
+
+ 1}
+ />
+
+ {index < columns?.length - 1 && }
+
+ ))}
+ {editing && (
+
+
+
+ Move row up
+
+
+
+ Add column
+
+
+
+ Remove row
+
+
+
+ Move row down
+
+
+ )}
+
+ );
+}
diff --git a/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx b/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx
new file mode 100644
index 000000000..756f39d28
--- /dev/null
+++ b/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx
@@ -0,0 +1,22 @@
+import { Text } from '@umami/react-zen';
+import { IconLabel } from '@/components/common/IconLabel';
+import { LinkButton } from '@/components/common/LinkButton';
+import { PageHeader } from '@/components/common/PageHeader';
+import { useBoard, useMessages, useNavigation, useWebsiteQuery } from '@/components/hooks';
+import { Edit } from '@/components/icons';
+
+export function BoardViewHeader() {
+ const { board } = useBoard();
+ const { renderUrl } = useNavigation();
+ const { formatMessage, labels } = useMessages();
+ const { data: website } = useWebsiteQuery(board?.parameters?.websiteId);
+
+ return (
+
+ {website?.name && {website.name}}
+
+ }>{formatMessage(labels.edit)}
+
+
+ );
+}
diff --git a/src/app/(main)/boards/[boardId]/boardConstants.ts b/src/app/(main)/boards/[boardId]/boardConstants.ts
new file mode 100644
index 000000000..91dabd536
--- /dev/null
+++ b/src/app/(main)/boards/[boardId]/boardConstants.ts
@@ -0,0 +1,5 @@
+export const MIN_ROW_HEIGHT = 300;
+export const MAX_ROW_HEIGHT = 600;
+export const MIN_COLUMN_WIDTH = 300;
+export const BUTTON_ROW_HEIGHT = 60;
+export const MAX_COLUMNS = 4;