Refine Dashboard Styles and Tab Functionality for Enhanced User Experience
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
- Adjusted CSS styles for dashboard elements, including margin and positioning tweaks for improved layout and visual consistency. - Updated tab masking logic to enhance scrolling behavior and visual integration. - Removed unnecessary divider components to streamline the dashboard navigation structure. - Implemented new logic for handling tab scrolling, ensuring better responsiveness and user interaction.
This commit is contained in:
parent
0b4b8128de
commit
48d2b0d15a
@ -175,13 +175,14 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
.dashboard-menu-container:after {
|
.dashboard-menu-container:after {
|
||||||
border-bottom: 1px solid var(--color-header-border);
|
border-bottom: 1px solid var(--color-header-border);
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: -8px;
|
||||||
right: -2px;
|
right: 0px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3483,6 +3484,10 @@ body.objectKanbanColumnResizing * {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
--tab-mask-left: 4px;
|
||||||
|
--tab-mask-right: 8px;
|
||||||
|
--tab-mask-fade-left: var(--tab-mask-fade);
|
||||||
|
--tab-mask-fade-right: var(--tab-mask-fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap .simplebar-content-wrapper {
|
.dashboard-tabs-wrap .simplebar-content-wrapper {
|
||||||
@ -3490,10 +3495,6 @@ body.objectKanbanColumnResizing * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap .simplebar-mask {
|
.dashboard-tabs-wrap .simplebar-mask {
|
||||||
--tab-mask-left: 4px;
|
|
||||||
--tab-mask-right: 4px;
|
|
||||||
--tab-mask-fade-left: var(--tab-mask-fade);
|
|
||||||
--tab-mask-fade-right: var(--tab-mask-fade);
|
|
||||||
-webkit-clip-path: inset(0 var(--tab-mask-right) 0 var(--tab-mask-left));
|
-webkit-clip-path: inset(0 var(--tab-mask-right) 0 var(--tab-mask-left));
|
||||||
clip-path: inset(0 var(--tab-mask-right) 0 var(--tab-mask-left));
|
clip-path: inset(0 var(--tab-mask-right) 0 var(--tab-mask-left));
|
||||||
-webkit-mask-image: linear-gradient(
|
-webkit-mask-image: linear-gradient(
|
||||||
@ -3512,12 +3513,12 @@ body.objectKanbanColumnResizing * {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs[data-at-start] .dashboard-tabs-wrap .simplebar-mask {
|
.dashboard-tabs[data-at-start] .dashboard-tabs-wrap {
|
||||||
--tab-mask-left: 0px;
|
--tab-mask-left: 0px;
|
||||||
--tab-mask-fade-left: 0px;
|
--tab-mask-fade-left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs[data-at-end] .dashboard-tabs-wrap .simplebar-mask {
|
.dashboard-tabs[data-at-end] .dashboard-tabs-wrap {
|
||||||
--tab-mask-right: 0px;
|
--tab-mask-right: 0px;
|
||||||
--tab-mask-fade-right: 0px;
|
--tab-mask-fade-right: 0px;
|
||||||
}
|
}
|
||||||
@ -3527,7 +3528,6 @@ body.objectKanbanColumnResizing * {
|
|||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: var(--tab-mask-fade);
|
|
||||||
height: 1px;
|
height: 1px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@ -3536,14 +3536,32 @@ body.objectKanbanColumnResizing * {
|
|||||||
|
|
||||||
.dashboard-tabs-wrap::before {
|
.dashboard-tabs-wrap::before {
|
||||||
left: 0;
|
left: 0;
|
||||||
-webkit-mask-image: linear-gradient(to right, #000, transparent);
|
width: calc(var(--tab-mask-left) + var(--tab-mask-fade-left));
|
||||||
mask-image: linear-gradient(to right, #000, transparent);
|
-webkit-mask-image: linear-gradient(
|
||||||
|
to right,
|
||||||
|
#000 var(--tab-mask-left),
|
||||||
|
transparent calc(var(--tab-mask-left) + var(--tab-mask-fade-left))
|
||||||
|
);
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to right,
|
||||||
|
#000 var(--tab-mask-left),
|
||||||
|
transparent calc(var(--tab-mask-left) + var(--tab-mask-fade-left))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap::after {
|
.dashboard-tabs-wrap::after {
|
||||||
right: 0.2px;
|
right: 0.2px;
|
||||||
-webkit-mask-image: linear-gradient(to left, #000, transparent);
|
width: calc(var(--tab-mask-right) + var(--tab-mask-fade-right));
|
||||||
mask-image: linear-gradient(to left, #000, transparent);
|
-webkit-mask-image: linear-gradient(
|
||||||
|
to left,
|
||||||
|
#000 var(--tab-mask-right),
|
||||||
|
transparent calc(var(--tab-mask-right) + var(--tab-mask-fade-right))
|
||||||
|
);
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to left,
|
||||||
|
#000 var(--tab-mask-right),
|
||||||
|
transparent calc(var(--tab-mask-right) + var(--tab-mask-fade-right))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap .simplebar-track.simplebar-vertical {
|
.dashboard-tabs-wrap .simplebar-track.simplebar-vertical {
|
||||||
|
|||||||
@ -78,14 +78,6 @@ const NAV_ELECTRON_CENTER_FADE_STYLE = {
|
|||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}
|
}
|
||||||
const NAV_ELECTRON_TABS_STYLE = { flex: 1, minWidth: 0, display: 'flex' }
|
const NAV_ELECTRON_TABS_STYLE = { flex: 1, minWidth: 0, display: 'flex' }
|
||||||
const NAV_ELECTRON_DIVIDER_STYLE_WITH_LABELS = {
|
|
||||||
margin: '3px 1px 0 4px',
|
|
||||||
height: '14px'
|
|
||||||
}
|
|
||||||
const NAV_ELECTRON_DIVIDER_STYLE = {
|
|
||||||
margin: '3px 1px 0 0',
|
|
||||||
height: '14px'
|
|
||||||
}
|
|
||||||
const NAV_TRAILING_FLEX_STYLE = { marginTop: '-2px', marginRight: '6px' }
|
const NAV_TRAILING_FLEX_STYLE = { marginTop: '-2px', marginRight: '6px' }
|
||||||
const NAV_TRAILING_SPACE_STYLE = { paddingTop: '2px', marginRight: '8px' }
|
const NAV_TRAILING_SPACE_STYLE = { paddingTop: '2px', marginRight: '8px' }
|
||||||
const NAV_SEARCH_BUTTON_STYLE = { marginTop: '4px' }
|
const NAV_SEARCH_BUTTON_STYLE = { marginTop: '4px' }
|
||||||
@ -237,14 +229,7 @@ const DashboardElectronCenterItems = memo(
|
|||||||
>
|
>
|
||||||
{menu}
|
{menu}
|
||||||
</div>
|
</div>
|
||||||
<Divider
|
|
||||||
type='vertical'
|
|
||||||
style={
|
|
||||||
showNavigationLabels
|
|
||||||
? NAV_ELECTRON_DIVIDER_STYLE_WITH_LABELS
|
|
||||||
: NAV_ELECTRON_DIVIDER_STYLE
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div style={NAV_ELECTRON_TABS_STYLE}>
|
<div style={NAV_ELECTRON_TABS_STYLE}>
|
||||||
<DashboardTabs />
|
<DashboardTabs />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||||
import { Button, Flex, Typography } from 'antd'
|
import { Button, Flex, Typography } from 'antd'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import ScrollBox from './ScrollBox'
|
import ScrollBox from './ScrollBox'
|
||||||
@ -177,17 +177,18 @@ const hideStickyClone = (cloneEl) => {
|
|||||||
|
|
||||||
const setSimplebarMaskInset = (maskEl, edge, inset) => {
|
const setSimplebarMaskInset = (maskEl, edge, inset) => {
|
||||||
if (!maskEl) return
|
if (!maskEl) return
|
||||||
|
const wrapEl = maskEl.closest('.dashboard-tabs-wrap') || maskEl
|
||||||
if (!edge) {
|
if (!edge) {
|
||||||
maskEl.style.removeProperty('--tab-mask-left')
|
wrapEl.style.removeProperty('--tab-mask-left')
|
||||||
maskEl.style.removeProperty('--tab-mask-right')
|
wrapEl.style.removeProperty('--tab-mask-right')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (edge === 'left') {
|
if (edge === 'left') {
|
||||||
maskEl.style.setProperty('--tab-mask-left', `${inset}px`)
|
wrapEl.style.setProperty('--tab-mask-left', `${inset}px`)
|
||||||
maskEl.style.removeProperty('--tab-mask-right')
|
wrapEl.style.removeProperty('--tab-mask-right')
|
||||||
} else {
|
} else {
|
||||||
maskEl.style.removeProperty('--tab-mask-left')
|
wrapEl.style.removeProperty('--tab-mask-left')
|
||||||
maskEl.style.setProperty('--tab-mask-right', `${inset}px`)
|
wrapEl.style.setProperty('--tab-mask-right', `${inset}px`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,6 +392,8 @@ const useActiveTabStickyScroll = (activeTabId, tabs) => {
|
|||||||
const listRef = useRef(null)
|
const listRef = useRef(null)
|
||||||
const cloneRef = useRef(null)
|
const cloneRef = useRef(null)
|
||||||
const lineRef = useRef(null)
|
const lineRef = useRef(null)
|
||||||
|
const prevTabCountRef = useRef(tabs.length)
|
||||||
|
const pendingScrollTabIdRef = useRef(null)
|
||||||
const tabLayoutKey = `${activeTabId}:${tabs.map((tab) => `${tab.id}:${tab.title || ''}`).join('|')}`
|
const tabLayoutKey = `${activeTabId}:${tabs.map((tab) => `${tab.id}:${tab.title || ''}`).join('|')}`
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -429,6 +432,46 @@ const useActiveTabStickyScroll = (activeTabId, tabs) => {
|
|||||||
}
|
}
|
||||||
}, [tabLayoutKey])
|
}, [tabLayoutKey])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const lastTab = tabs[tabs.length - 1]
|
||||||
|
if (
|
||||||
|
tabs.length === prevTabCountRef.current + 1 &&
|
||||||
|
lastTab?.id === activeTabId
|
||||||
|
) {
|
||||||
|
pendingScrollTabIdRef.current = lastTab.id
|
||||||
|
}
|
||||||
|
prevTabCountRef.current = tabs.length
|
||||||
|
|
||||||
|
if (!lastTab || pendingScrollTabIdRef.current !== lastTab.id) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = listRef.current
|
||||||
|
const scrollEl = rootRef.current?.querySelector(
|
||||||
|
'.simplebar-content-wrapper'
|
||||||
|
)
|
||||||
|
const outlineEl = list?.lastElementChild?.querySelector(
|
||||||
|
'.dashboard-tab-item-outline-container'
|
||||||
|
)
|
||||||
|
if (!scrollEl || !outlineEl) return undefined
|
||||||
|
|
||||||
|
const scrollToEndIfReady = () => {
|
||||||
|
if (outlineEl.getBoundingClientRect().width <= 36) return false
|
||||||
|
scrollEl.scrollLeft = scrollEl.scrollWidth
|
||||||
|
pendingScrollTabIdRef.current = null
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollToEndIfReady()) return undefined
|
||||||
|
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
if (scrollToEndIfReady()) observer.disconnect()
|
||||||
|
})
|
||||||
|
observer.observe(outlineEl)
|
||||||
|
|
||||||
|
return () => observer.disconnect()
|
||||||
|
}, [activeTabId, tabs])
|
||||||
|
|
||||||
return { rootRef, listRef, cloneRef, lineRef }
|
return { rootRef, listRef, cloneRef, lineRef }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user