mirror of
https://github.com/umami-software/umami.git
synced 2026-02-15 18:15:35 +01:00
Migrate board layout UI to react-zen and preserve empty component titles
This commit is contained in:
parent
db637864f6
commit
cda9c684c3
9 changed files with 168 additions and 177 deletions
|
|
@ -1,17 +0,0 @@
|
||||||
.column {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.columnAction {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 120ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column:hover .columnAction,
|
|
||||||
.column:focus-within .columnAction {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
@ -73,14 +73,14 @@ export function BoardComponentSelect({
|
||||||
|
|
||||||
setSelectedDef(definition);
|
setSelectedDef(definition);
|
||||||
setConfigValues(getDefaultConfigValues(definition, initialConfig));
|
setConfigValues(getDefaultConfigValues(definition, initialConfig));
|
||||||
setTitle(initialConfig.title || definition.name);
|
setTitle(initialConfig.title ?? '');
|
||||||
setDescription(initialConfig.description || '');
|
setDescription(initialConfig.description || '');
|
||||||
}, [initialConfig, allDefinitions]);
|
}, [initialConfig, allDefinitions]);
|
||||||
|
|
||||||
const handleSelectComponent = (def: ComponentDefinition) => {
|
const handleSelectComponent = (def: ComponentDefinition) => {
|
||||||
setSelectedDef(def);
|
setSelectedDef(def);
|
||||||
setConfigValues(getDefaultConfigValues(def));
|
setConfigValues(getDefaultConfigValues(def));
|
||||||
setTitle(def.name);
|
setTitle('');
|
||||||
setDescription('');
|
setDescription('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ export function BoardComponentSelect({
|
||||||
|
|
||||||
const config: BoardComponentConfig = {
|
const config: BoardComponentConfig = {
|
||||||
type: selectedDef.type,
|
type: selectedDef.type,
|
||||||
title: title || selectedDef.name,
|
title,
|
||||||
description,
|
description,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -248,7 +248,7 @@ export function BoardComponentSelect({
|
||||||
{t(labels.cancel)}
|
{t(labels.cancel)}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" onPress={handleAdd} isDisabled={!selectedDef}>
|
<Button variant="primary" onPress={handleAdd} isDisabled={!selectedDef}>
|
||||||
{t(labels.add)}
|
{t(labels.save)}
|
||||||
</Button>
|
</Button>
|
||||||
</Row>
|
</Row>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import { Button, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
import { Box, Button, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
import { Fragment, useEffect, useRef } from 'react';
|
import { Fragment, useEffect, useRef } from 'react';
|
||||||
import { Group, type GroupImperativeHandle, Panel, Separator } from 'react-resizable-panels';
|
import { Group, type GroupImperativeHandle, Panel, Separator } from 'react-resizable-panels';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { useBoard } from '@/components/hooks';
|
import { useBoard } from '@/components/hooks';
|
||||||
import { GripHorizontal, Plus } from '@/components/icons';
|
import { GripHorizontal, Plus } from '@/components/icons';
|
||||||
import styles from './BoardEditLayout.module.css';
|
|
||||||
import { BoardEditRow } from './BoardEditRow';
|
import { BoardEditRow } from './BoardEditRow';
|
||||||
import { BUTTON_ROW_HEIGHT, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT } from './boardConstants';
|
import { BUTTON_ROW_HEIGHT, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT } from './boardConstants';
|
||||||
|
|
||||||
|
|
@ -108,52 +107,71 @@ export function BoardEditBody() {
|
||||||
const minHeight = (rows.length || 1) * MAX_ROW_HEIGHT + BUTTON_ROW_HEIGHT;
|
const minHeight = (rows.length || 1) * MAX_ROW_HEIGHT + BUTTON_ROW_HEIGHT;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group groupRef={rowGroupRef} orientation="vertical" style={{ minHeight }}>
|
<Box minHeight={`${minHeight}px`}>
|
||||||
{rows.map((row, index) => (
|
<Group groupRef={rowGroupRef} orientation="vertical">
|
||||||
<Fragment key={`${row.id}:${row.size ?? 'auto'}`}>
|
{rows.map((row, index) => (
|
||||||
<Panel
|
<Fragment key={`${row.id}:${row.size ?? 'auto'}`}>
|
||||||
id={row.id}
|
<Panel
|
||||||
minSize={MIN_ROW_HEIGHT}
|
id={row.id}
|
||||||
maxSize={MAX_ROW_HEIGHT}
|
minSize={MIN_ROW_HEIGHT}
|
||||||
defaultSize={row.size != null ? `${row.size}%` : undefined}
|
maxSize={MAX_ROW_HEIGHT}
|
||||||
>
|
defaultSize={row.size != null ? `${row.size}%` : undefined}
|
||||||
<BoardEditRow
|
>
|
||||||
{...row}
|
<BoardEditRow
|
||||||
rowId={row.id}
|
{...row}
|
||||||
rowIndex={index}
|
rowId={row.id}
|
||||||
rowCount={rows.length}
|
rowIndex={index}
|
||||||
canEdit={!!websiteId}
|
rowCount={rows.length}
|
||||||
onRemove={handleRemoveRow}
|
canEdit={!!websiteId}
|
||||||
onMoveUp={handleMoveRowUp}
|
onRemove={handleRemoveRow}
|
||||||
onMoveDown={handleMoveRowDown}
|
onMoveUp={handleMoveRowUp}
|
||||||
onRegisterRef={registerColumnGroupRef}
|
onMoveDown={handleMoveRowDown}
|
||||||
/>
|
onRegisterRef={registerColumnGroupRef}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
{index < rows.length - 1 && (
|
||||||
|
<Separator
|
||||||
|
style={{
|
||||||
|
height: '12px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
background: 'transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
style={{ cursor: 'row-resize' }}
|
||||||
|
>
|
||||||
|
<Icon size="sm">
|
||||||
|
<GripHorizontal />
|
||||||
|
</Icon>
|
||||||
|
</Row>
|
||||||
|
</Separator>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
{!!websiteId && (
|
||||||
|
<Panel minSize={BUTTON_ROW_HEIGHT}>
|
||||||
|
<Row padding="3">
|
||||||
|
<TooltipTrigger delay={0}>
|
||||||
|
<Button variant="outline" onPress={handleAddRow}>
|
||||||
|
<Icon>
|
||||||
|
<Plus />
|
||||||
|
</Icon>
|
||||||
|
</Button>
|
||||||
|
<Tooltip placement="bottom">Add row</Tooltip>
|
||||||
|
</TooltipTrigger>
|
||||||
|
</Row>
|
||||||
</Panel>
|
</Panel>
|
||||||
{index < rows.length - 1 && (
|
)}
|
||||||
<Separator className={styles.rowSeparator}>
|
</Group>
|
||||||
<span className={styles.separatorHandle}>
|
</Box>
|
||||||
<Icon size="sm">
|
|
||||||
<GripHorizontal />
|
|
||||||
</Icon>
|
|
||||||
</span>
|
|
||||||
</Separator>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
|
||||||
))}
|
|
||||||
{!!websiteId && (
|
|
||||||
<Panel minSize={BUTTON_ROW_HEIGHT}>
|
|
||||||
<Row padding="3">
|
|
||||||
<TooltipTrigger delay={0}>
|
|
||||||
<Button variant="outline" onPress={handleAddRow}>
|
|
||||||
<Icon>
|
|
||||||
<Plus />
|
|
||||||
</Icon>
|
|
||||||
</Button>
|
|
||||||
<Tooltip placement="bottom">Add row</Tooltip>
|
|
||||||
</TooltipTrigger>
|
|
||||||
</Row>
|
|
||||||
</Panel>
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,20 @@
|
||||||
import { Box, Button, Dialog, Icon, Modal, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Column,
|
||||||
|
Dialog,
|
||||||
|
Icon,
|
||||||
|
Modal,
|
||||||
|
Row,
|
||||||
|
Tooltip,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@umami/react-zen';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { Panel } from '@/components/common/Panel';
|
import { Panel } from '@/components/common/Panel';
|
||||||
import { useBoard, useMessages } from '@/components/hooks';
|
import { useBoard, useMessages } from '@/components/hooks';
|
||||||
import { Pencil, Plus, X } from '@/components/icons';
|
import { Pencil, Plus, X } from '@/components/icons';
|
||||||
import type { BoardComponentConfig } from '@/lib/types';
|
import type { BoardComponentConfig } from '@/lib/types';
|
||||||
import { getComponentDefinition } from '../boardComponentRegistry';
|
import { getComponentDefinition } from '../boardComponentRegistry';
|
||||||
import styles from './BoardColumn.module.css';
|
|
||||||
import { BoardComponentRenderer } from './BoardComponentRenderer';
|
import { BoardComponentRenderer } from './BoardComponentRenderer';
|
||||||
import { BoardComponentSelect } from './BoardComponentSelect';
|
import { BoardComponentSelect } from './BoardComponentSelect';
|
||||||
|
|
||||||
|
|
@ -25,6 +34,7 @@ export function BoardEditColumn({
|
||||||
canRemove?: boolean;
|
canRemove?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [showSelect, setShowSelect] = useState(false);
|
const [showSelect, setShowSelect] = useState(false);
|
||||||
|
const [showActions, setShowActions] = useState(false);
|
||||||
const { board } = useBoard();
|
const { board } = useBoard();
|
||||||
const { t, labels } = useMessages();
|
const { t, labels } = useMessages();
|
||||||
const websiteId = board?.parameters?.websiteId;
|
const websiteId = board?.parameters?.websiteId;
|
||||||
|
|
@ -44,7 +54,7 @@ export function BoardEditColumn({
|
||||||
const hasComponent = !!component;
|
const hasComponent = !!component;
|
||||||
const canRemoveAction = hasComponent || canRemove;
|
const canRemoveAction = hasComponent || canRemove;
|
||||||
const defaultTitle = component ? getComponentDefinition(component.type)?.name : undefined;
|
const defaultTitle = component ? getComponentDefinition(component.type)?.name : undefined;
|
||||||
const title = component?.title || defaultTitle;
|
const title = component?.title ?? defaultTitle;
|
||||||
const description = component?.description;
|
const description = component?.description;
|
||||||
|
|
||||||
const handleRemove = () => {
|
const handleRemove = () => {
|
||||||
|
|
@ -62,16 +72,11 @@ export function BoardEditColumn({
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
position="relative"
|
position="relative"
|
||||||
className={styles.column}
|
onMouseEnter={() => setShowActions(true)}
|
||||||
|
onMouseLeave={() => setShowActions(false)}
|
||||||
>
|
>
|
||||||
{canEdit && canRemoveAction && (
|
{canEdit && canRemoveAction && showActions && (
|
||||||
<Box
|
<Box position="absolute" top="22px" right="24px" zIndex={100}>
|
||||||
className={styles.columnAction}
|
|
||||||
position="absolute"
|
|
||||||
top="22px"
|
|
||||||
right="24px"
|
|
||||||
zIndex={100}
|
|
||||||
>
|
|
||||||
<Row gap="2">
|
<Row gap="2">
|
||||||
{hasComponent && (
|
{hasComponent && (
|
||||||
<TooltipTrigger delay={0}>
|
<TooltipTrigger delay={0}>
|
||||||
|
|
@ -100,17 +105,13 @@ export function BoardEditColumn({
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
canEdit && (
|
canEdit && (
|
||||||
<Box
|
<Column width="100%" height="100%" alignItems="center" justifyContent="center">
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
|
|
||||||
>
|
|
||||||
<Button variant="outline" onPress={() => setShowSelect(true)}>
|
<Button variant="outline" onPress={() => setShowSelect(true)}>
|
||||||
<Icon>
|
<Icon>
|
||||||
<Plus />
|
<Plus />
|
||||||
</Icon>
|
</Icon>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Column>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
<Modal isOpen={showSelect} onOpenChange={setShowSelect}>
|
<Modal isOpen={showSelect} onOpenChange={setShowSelect}>
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
.columnSeparator {
|
|
||||||
width: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: col-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowSeparator {
|
|
||||||
height: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: row-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separatorHandle {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: var(--gray-9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowGroup {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowActions {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 12px;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
z-index: 20;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 120ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowGroup:hover .rowActions,
|
|
||||||
.rowGroup:focus-within .rowActions {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Button, Column, Icon, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
import { Box, Button, Column, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
import { Fragment } from 'react';
|
import { Fragment, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Group,
|
Group,
|
||||||
type GroupImperativeHandle,
|
type GroupImperativeHandle,
|
||||||
|
|
@ -12,7 +12,6 @@ import { useBoard } from '@/components/hooks';
|
||||||
import { ChevronDown, GripVertical, Minus, Plus } from '@/components/icons';
|
import { ChevronDown, GripVertical, Minus, Plus } from '@/components/icons';
|
||||||
import type { BoardColumn as BoardColumnType, BoardComponentConfig } from '@/lib/types';
|
import type { BoardColumn as BoardColumnType, BoardComponentConfig } from '@/lib/types';
|
||||||
import { BoardEditColumn } from './BoardEditColumn';
|
import { BoardEditColumn } from './BoardEditColumn';
|
||||||
import styles from './BoardEditLayout.module.css';
|
|
||||||
import { MAX_COLUMNS, MIN_COLUMN_WIDTH } from './boardConstants';
|
import { MAX_COLUMNS, MIN_COLUMN_WIDTH } from './boardConstants';
|
||||||
|
|
||||||
export function BoardEditRow({
|
export function BoardEditRow({
|
||||||
|
|
@ -37,6 +36,7 @@ export function BoardEditRow({
|
||||||
onRegisterRef: (rowId: string, ref: GroupImperativeHandle | null) => void;
|
onRegisterRef: (rowId: string, ref: GroupImperativeHandle | null) => void;
|
||||||
}) {
|
}) {
|
||||||
const { board, updateBoard } = useBoard();
|
const { board, updateBoard } = useBoard();
|
||||||
|
const [showActions, setShowActions] = useState(false);
|
||||||
|
|
||||||
const handleGroupRef = (ref: GroupImperativeHandle | null) => {
|
const handleGroupRef = (ref: GroupImperativeHandle | null) => {
|
||||||
onRegisterRef(rowId, ref);
|
onRegisterRef(rowId, ref);
|
||||||
|
|
@ -82,35 +82,68 @@ export function BoardEditRow({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group groupRef={handleGroupRef} className={styles.rowGroup}>
|
<Box
|
||||||
{columns?.map((column, index) => (
|
position="relative"
|
||||||
<Fragment key={`${column.id}:${column.size ?? 'auto'}`}>
|
height="100%"
|
||||||
<ResizablePanel
|
onMouseEnter={() => setShowActions(true)}
|
||||||
id={column.id}
|
onMouseLeave={() => setShowActions(false)}
|
||||||
minSize={MIN_COLUMN_WIDTH}
|
>
|
||||||
defaultSize={column.size != null ? `${column.size}%` : undefined}
|
<Group groupRef={handleGroupRef}>
|
||||||
>
|
{columns?.map((column, index) => (
|
||||||
<BoardEditColumn
|
<Fragment key={`${column.id}:${column.size ?? 'auto'}`}>
|
||||||
{...column}
|
<ResizablePanel
|
||||||
canEdit={canEdit}
|
id={column.id}
|
||||||
onRemove={handleRemoveColumn}
|
minSize={MIN_COLUMN_WIDTH}
|
||||||
onSetComponent={handleSetComponent}
|
defaultSize={column.size != null ? `${column.size}%` : undefined}
|
||||||
canRemove={columns.length > 1}
|
>
|
||||||
/>
|
<BoardEditColumn
|
||||||
</ResizablePanel>
|
{...column}
|
||||||
{index < columns.length - 1 && (
|
canEdit={canEdit}
|
||||||
<Separator className={styles.columnSeparator}>
|
onRemove={handleRemoveColumn}
|
||||||
<span className={styles.separatorHandle}>
|
onSetComponent={handleSetComponent}
|
||||||
<Icon size="sm">
|
canRemove={columns.length > 1}
|
||||||
<GripVertical />
|
/>
|
||||||
</Icon>
|
</ResizablePanel>
|
||||||
</span>
|
{index < columns.length - 1 && (
|
||||||
</Separator>
|
<Separator
|
||||||
)}
|
style={{
|
||||||
</Fragment>
|
width: '12px',
|
||||||
))}
|
display: 'flex',
|
||||||
{canEdit && (
|
alignItems: 'center',
|
||||||
<Column className={styles.rowActions} padding="3" gap="1">
|
justifyContent: 'center',
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
background: 'transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
style={{ cursor: 'col-resize' }}
|
||||||
|
>
|
||||||
|
<Icon size="sm">
|
||||||
|
<GripVertical />
|
||||||
|
</Icon>
|
||||||
|
</Row>
|
||||||
|
</Separator>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</Group>
|
||||||
|
{canEdit && showActions && (
|
||||||
|
<Column
|
||||||
|
padding="3"
|
||||||
|
gap="1"
|
||||||
|
position="absolute"
|
||||||
|
top="0"
|
||||||
|
bottom="0"
|
||||||
|
right="12px"
|
||||||
|
zIndex={20}
|
||||||
|
justifyContent="center"
|
||||||
|
>
|
||||||
<TooltipTrigger delay={0}>
|
<TooltipTrigger delay={0}>
|
||||||
<Button variant="outline" onPress={() => onMoveUp(rowId)} isDisabled={rowIndex === 0}>
|
<Button variant="outline" onPress={() => onMoveUp(rowId)} isDisabled={rowIndex === 0}>
|
||||||
<Icon rotate={180}>
|
<Icon rotate={180}>
|
||||||
|
|
@ -153,6 +186,6 @@ export function BoardEditRow({
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
</Column>
|
</Column>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Column } from '@umami/react-zen';
|
||||||
import { useBoard } from '@/components/hooks';
|
import { useBoard } from '@/components/hooks';
|
||||||
import { BoardViewRow } from './BoardViewRow';
|
import { BoardViewRow } from './BoardViewRow';
|
||||||
|
|
||||||
|
|
@ -6,10 +7,10 @@ export function BoardViewBody() {
|
||||||
const rows = board?.parameters?.rows ?? [];
|
const rows = board?.parameters?.rows ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
<Column gap="3">
|
||||||
{rows.map(row => (
|
{rows.map(row => (
|
||||||
<BoardViewRow key={row.id} columns={row.columns} />
|
<BoardViewRow key={row.id} columns={row.columns} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export function BoardViewColumn({ component }: { component?: BoardComponentConfi
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = component.title || getComponentDefinition(component.type)?.name;
|
const title = component.title ?? getComponentDefinition(component.type)?.name;
|
||||||
const description = component.description;
|
const description = component.description;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
|
import { Box, Row } from '@umami/react-zen';
|
||||||
import type { BoardColumn } from '@/lib/types';
|
import type { BoardColumn } from '@/lib/types';
|
||||||
import { BoardViewColumn } from './BoardViewColumn';
|
import { BoardViewColumn } from './BoardViewColumn';
|
||||||
import { MIN_COLUMN_WIDTH } from './boardConstants';
|
import { MIN_COLUMN_WIDTH } from './boardConstants';
|
||||||
|
|
||||||
export function BoardViewRow({ columns }: { columns: BoardColumn[] }) {
|
export function BoardViewRow({ columns }: { columns: BoardColumn[] }) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', gap: 12, width: '100%', overflowX: 'auto' }}>
|
<Row gap="3" width="100%" overflowX="auto">
|
||||||
{columns.map(column => (
|
{columns.map(column => (
|
||||||
<div
|
<Box
|
||||||
key={column.id}
|
key={column.id}
|
||||||
style={{
|
flexGrow={column.size ?? 1}
|
||||||
flex: `${column.size ?? 1} 1 0%`,
|
flexShrink={1}
|
||||||
minWidth: MIN_COLUMN_WIDTH,
|
flexBasis="0%"
|
||||||
}}
|
minWidth={`${MIN_COLUMN_WIDTH}px`}
|
||||||
>
|
>
|
||||||
<BoardViewColumn component={column.component} />
|
<BoardViewColumn component={column.component} />
|
||||||
</div>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</div>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue