Enhance DashboardOverviewFlexColumns with Vertical Layout Support
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Added functionality to toggle between vertical and horizontal layouts in the DashboardOverviewFlexColumns component, improving responsiveness based on available space. - Implemented useLayoutEffect to manage layout changes dynamically, ensuring optimal display of child components. - Updated CSS styles to support the new vertical layout, enhancing the overall user experience in the dashboard.
This commit is contained in:
parent
e3a20e6b48
commit
b347ec3637
@ -2005,6 +2005,12 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overview-flex-columns.is-vertical .overview-flex-columns-item {
|
||||||
|
flex: none;
|
||||||
|
width: 100%;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
.overview-flex-columns-empty {
|
.overview-flex-columns-empty {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
isValidElement,
|
isValidElement,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
@ -55,8 +56,114 @@ const DashboardOverviewFlexColumns = ({
|
|||||||
[childList.length, proportions]
|
[childList.length, proportions]
|
||||||
)
|
)
|
||||||
const dragRef = useRef(null)
|
const dragRef = useRef(null)
|
||||||
|
const rowRef = useRef(null)
|
||||||
const onProportionsChangeRef = useRef(onProportionsChange)
|
const onProportionsChangeRef = useRef(onProportionsChange)
|
||||||
|
const stackAtWidthRef = useRef(null)
|
||||||
|
const isVerticalRef = useRef(false)
|
||||||
const [activeSeparator, setActiveSeparator] = useState(null)
|
const [activeSeparator, setActiveSeparator] = useState(null)
|
||||||
|
const [isVertical, setIsVertical] = useState(false)
|
||||||
|
|
||||||
|
const setVertical = useCallback((next) => {
|
||||||
|
isVerticalRef.current = next
|
||||||
|
setIsVertical((previous) => (previous === next ? previous : next))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const row = rowRef.current
|
||||||
|
if (!row || isEmpty) {
|
||||||
|
stackAtWidthRef.current = null
|
||||||
|
setVertical(false)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasHorizontalOverflow = (items) => {
|
||||||
|
if (row.scrollWidth > row.clientWidth + 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.some((item) => item.scrollWidth > item.clientWidth + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let frame = null
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
const rowWidth = row.clientWidth
|
||||||
|
if (rowWidth < 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const flexEl = row.firstElementChild
|
||||||
|
if (!flexEl) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = [...row.querySelectorAll('.overview-flex-columns-item')]
|
||||||
|
if (!items.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const stackState = stackAtWidthRef.current
|
||||||
|
|
||||||
|
if (!isVerticalRef.current) {
|
||||||
|
if (
|
||||||
|
stackState &&
|
||||||
|
stackState.childCount === items.length &&
|
||||||
|
rowWidth > stackState.width
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasHorizontalOverflow(items)) {
|
||||||
|
stackAtWidthRef.current = {
|
||||||
|
width: rowWidth,
|
||||||
|
childCount: items.length
|
||||||
|
}
|
||||||
|
setVertical(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
stackAtWidthRef.current = null
|
||||||
|
setVertical(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stackState || stackState.childCount !== items.length) {
|
||||||
|
stackAtWidthRef.current = null
|
||||||
|
setVertical(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowWidth > stackState.width) {
|
||||||
|
setVertical(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduleUpdate = () => {
|
||||||
|
if (frame != null) {
|
||||||
|
cancelAnimationFrame(frame)
|
||||||
|
}
|
||||||
|
frame = requestAnimationFrame(() => {
|
||||||
|
frame = null
|
||||||
|
update()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleUpdate()
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(scheduleUpdate)
|
||||||
|
resizeObserver.observe(row)
|
||||||
|
|
||||||
|
row.querySelectorAll('.overview-flex-columns-item').forEach((item) => {
|
||||||
|
resizeObserver.observe(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (frame != null) {
|
||||||
|
cancelAnimationFrame(frame)
|
||||||
|
}
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
}, [childList, isEmpty, resolvedProportions, setVertical])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onProportionsChangeRef.current = onProportionsChange
|
onProportionsChangeRef.current = onProportionsChange
|
||||||
@ -170,7 +277,9 @@ const DashboardOverviewFlexColumns = ({
|
|||||||
isLayoutEditing ? 'is-editing' : ''
|
isLayoutEditing ? 'is-editing' : ''
|
||||||
} ${isDragOver ? 'is-drag-over' : ''} ${
|
} ${isDragOver ? 'is-drag-over' : ''} ${
|
||||||
isEmpty && isLayoutEditing ? 'is-empty' : ''
|
isEmpty && isLayoutEditing ? 'is-empty' : ''
|
||||||
} ${activeSeparator != null ? 'is-resizing' : ''}`}
|
} ${activeSeparator != null ? 'is-resizing' : ''} ${
|
||||||
|
isVertical ? 'is-vertical' : ''
|
||||||
|
}`}
|
||||||
onDragOver={onDragOver}
|
onDragOver={onDragOver}
|
||||||
onDrop={onDrop}
|
onDrop={onDrop}
|
||||||
onDragLeave={onDragLeave}
|
onDragLeave={onDragLeave}
|
||||||
@ -195,44 +304,48 @@ const DashboardOverviewFlexColumns = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
<Flex
|
<div ref={rowRef} className='overview-flex-columns-row'>
|
||||||
gap='large'
|
<Flex
|
||||||
align='stretch'
|
vertical={isVertical}
|
||||||
className='overview-flex-columns-row'
|
gap='large'
|
||||||
wrap='nowrap'
|
align='stretch'
|
||||||
>
|
wrap='nowrap'
|
||||||
{isEmpty && isLayoutEditing ? (
|
style={{ width: '100%' }}
|
||||||
<div className='overview-flex-columns-empty'>Drop sections here</div>
|
>
|
||||||
) : (
|
{isEmpty && isLayoutEditing ? (
|
||||||
childList.map((child, index) => {
|
<div className='overview-flex-columns-empty'>Drop sections here</div>
|
||||||
if (!isValidElement(child)) return child
|
) : (
|
||||||
const proportion = resolvedProportions[index] ?? 0
|
childList.map((child, index) => {
|
||||||
const showSeparator =
|
if (!isValidElement(child)) return child
|
||||||
isLayoutEditing && index < childList.length - 1
|
const proportion = resolvedProportions[index] ?? 0
|
||||||
return cloneElement(child, {
|
const showSeparator =
|
||||||
style: {
|
!isVertical && isLayoutEditing && index < childList.length - 1
|
||||||
...child.props.style,
|
return cloneElement(child, {
|
||||||
flex: `${proportion} 1 0`,
|
style: {
|
||||||
minWidth: 0,
|
...child.props.style,
|
||||||
position: 'relative'
|
...(isVertical
|
||||||
},
|
? { width: '100%', flex: 'none' }
|
||||||
children: (
|
: { flex: `${proportion} 1 0`, minWidth: 0 }),
|
||||||
<>
|
position: 'relative'
|
||||||
{child.props.children}
|
},
|
||||||
{showSeparator ? (
|
children: (
|
||||||
<ColumnSeparator
|
<>
|
||||||
active={activeSeparator === index}
|
{child.props.children}
|
||||||
onPointerDown={(event) =>
|
{showSeparator ? (
|
||||||
handlePointerDown(event, index)
|
<ColumnSeparator
|
||||||
}
|
active={activeSeparator === index}
|
||||||
/>
|
onPointerDown={(event) =>
|
||||||
) : null}
|
handlePointerDown(event, index)
|
||||||
</>
|
}
|
||||||
)
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
)}
|
||||||
)}
|
</Flex>
|
||||||
</Flex>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user