From d8c41ac8a6abe67fc67b94336f2f7bb1dddc9c1c Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 12 Feb 2026 22:36:23 -0800 Subject: [PATCH] Split board view/edit rendering and isolate edit interactions --- src/app/(main)/boards/BoardProvider.tsx | 2 +- .../(main)/boards/[boardId]/BoardControls.tsx | 18 ++++++ .../{BoardBody.tsx => BoardEditBody.tsx} | 31 ++++++---- .../{BoardColumn.tsx => BoardEditColumn.tsx} | 42 ++++++-------- .../[boardId]/BoardEditLayout.module.css | 46 +++++++++++++++ .../(main)/boards/[boardId]/BoardEditPage.tsx | 21 +++++++ .../{BoardRow.tsx => BoardEditRow.tsx} | 57 +++++++++++-------- .../(main)/boards/[boardId]/BoardHeader.tsx | 13 ----- src/app/(main)/boards/[boardId]/BoardPage.tsx | 33 ----------- .../(main)/boards/[boardId]/BoardViewBody.tsx | 15 +++++ .../boards/[boardId]/BoardViewColumn.tsx | 27 +++++++++ .../(main)/boards/[boardId]/BoardViewPage.tsx | 21 +++++++ .../(main)/boards/[boardId]/BoardViewRow.tsx | 21 +++++++ src/app/(main)/boards/[boardId]/edit/page.tsx | 4 +- src/app/(main)/boards/[boardId]/page.tsx | 9 ++- 15 files changed, 249 insertions(+), 111 deletions(-) create mode 100644 src/app/(main)/boards/[boardId]/BoardControls.tsx rename src/app/(main)/boards/[boardId]/{BoardBody.tsx => BoardEditBody.tsx} (84%) rename src/app/(main)/boards/[boardId]/{BoardColumn.tsx => BoardEditColumn.tsx} (82%) create mode 100644 src/app/(main)/boards/[boardId]/BoardEditLayout.module.css create mode 100644 src/app/(main)/boards/[boardId]/BoardEditPage.tsx rename src/app/(main)/boards/[boardId]/{BoardRow.tsx => BoardEditRow.tsx} (69%) delete mode 100644 src/app/(main)/boards/[boardId]/BoardHeader.tsx delete mode 100644 src/app/(main)/boards/[boardId]/BoardPage.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardViewBody.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardViewColumn.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardViewPage.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardViewRow.tsx diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx index e2a60819f..d0490163e 100644 --- a/src/app/(main)/boards/BoardProvider.tsx +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -99,7 +99,7 @@ export function BoardProvider({ const saveBoard = useCallback(async () => { const defaultName = t(labels.untitled); - // Get current layout sizes from BoardBody if registered + // Get current layout sizes from BoardEditBody if registered const layoutData = layoutGetterRef.current?.(); const parameters = sanitizeBoardParameters( layoutData ? { ...board.parameters, ...layoutData } : board.parameters, diff --git a/src/app/(main)/boards/[boardId]/BoardControls.tsx b/src/app/(main)/boards/[boardId]/BoardControls.tsx new file mode 100644 index 000000000..aed80020b --- /dev/null +++ b/src/app/(main)/boards/[boardId]/BoardControls.tsx @@ -0,0 +1,18 @@ +import { Box } from '@umami/react-zen'; +import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; +import { useBoard } from '@/components/hooks'; + +export function BoardControls() { + const { board } = useBoard(); + const websiteId = board?.parameters?.websiteId; + + if (!websiteId) { + return null; + } + + return ( + + + + ); +} diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardEditBody.tsx similarity index 84% rename from src/app/(main)/boards/[boardId]/BoardBody.tsx rename to src/app/(main)/boards/[boardId]/BoardEditBody.tsx index e3c363cb3..9e660e69b 100644 --- a/src/app/(main)/boards/[boardId]/BoardBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardEditBody.tsx @@ -4,16 +4,16 @@ 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 { Plus } from '@/components/icons'; -import { BoardRow } from './BoardRow'; +import { GripHorizontal, Plus } from '@/components/icons'; +import styles from './BoardEditLayout.module.css'; +import { BoardEditRow } from './BoardEditRow'; import { BUTTON_ROW_HEIGHT, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT } from './boardConstants'; -export function BoardBody() { - const { board, editing, updateBoard, saveBoard, isPending, registerLayoutGetter } = useBoard(); +export function BoardEditBody() { + const { board, updateBoard, registerLayoutGetter } = useBoard(); const rowGroupRef = useRef(null); const columnGroupRefs = useRef>(new Map()); - // Register a function to get current layout sizes on save useEffect(() => { registerLayoutGetter(() => { const rows = board?.parameters?.rows; @@ -104,9 +104,8 @@ export function BoardBody() { }; const websiteId = board?.parameters?.websiteId; - const canEdit = editing && !!websiteId; const rows = board?.parameters?.rows ?? []; - const minHeight = (rows?.length || 1) * MAX_ROW_HEIGHT + BUTTON_ROW_HEIGHT; + const minHeight = (rows.length || 1) * MAX_ROW_HEIGHT + BUTTON_ROW_HEIGHT; return ( @@ -118,22 +117,30 @@ export function BoardBody() { maxSize={MAX_ROW_HEIGHT} defaultSize={row.size} > - - {index < rows?.length - 1 && } + {index < rows.length - 1 && ( + + + + + + + + )} ))} - {canEdit && ( + {!!websiteId && ( diff --git a/src/app/(main)/boards/[boardId]/BoardColumn.tsx b/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx similarity index 82% rename from src/app/(main)/boards/[boardId]/BoardColumn.tsx rename to src/app/(main)/boards/[boardId]/BoardEditColumn.tsx index 334178d78..84c488c1a 100644 --- a/src/app/(main)/boards/[boardId]/BoardColumn.tsx +++ b/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx @@ -1,34 +1,27 @@ -import { - Box, - Button, - Column, - Dialog, - Icon, - Modal, - Tooltip, - TooltipTrigger, -} from '@umami/react-zen'; +import { Box, Button, Dialog, Icon, Modal, Tooltip, TooltipTrigger } from '@umami/react-zen'; import { useMemo, useState } from 'react'; +import { Panel } from '@/components/common/Panel'; import { useBoard, useMessages } from '@/components/hooks'; import { Pencil, Plus, X } from '@/components/icons'; import type { BoardComponentConfig } from '@/lib/types'; +import { getComponentDefinition } from '../boardComponentRegistry'; import styles from './BoardColumn.module.css'; import { BoardComponentRenderer } from './BoardComponentRenderer'; import { BoardComponentSelect } from './BoardComponentSelect'; -export function BoardColumn({ +export function BoardEditColumn({ id, component, - editing = false, + canEdit, onRemove, onSetComponent, canRemove = true, }: { id: string; component?: BoardComponentConfig; - editing?: boolean; - onRemove?: (id: string) => void; - onSetComponent?: (id: string, config: BoardComponentConfig | null) => void; + canEdit: boolean; + onRemove: (id: string) => void; + onSetComponent: (id: string, config: BoardComponentConfig | null) => void; canRemove?: boolean; }) { const [showSelect, setShowSelect] = useState(false); @@ -44,32 +37,33 @@ export function BoardColumn({ }, [component, websiteId]); const handleSelect = (config: BoardComponentConfig) => { - onSetComponent?.(id, config); + onSetComponent(id, config); setShowSelect(false); }; const hasComponent = !!component; const canRemoveAction = hasComponent || canRemove; + const title = component ? getComponentDefinition(component.type)?.name : undefined; const handleRemove = () => { if (hasComponent) { - onSetComponent?.(id, null); + onSetComponent(id, null); } else { - onRemove?.(id); + onRemove(id); } }; return ( - - {editing && canRemoveAction && ( + {canEdit && canRemoveAction && ( {renderedComponent} - {editing && ( + {canEdit && ( ) : ( - editing && ( + canEdit && (