Refactor Dashboard Tabs and Enhance CSS Styles
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
- Updated CSS for dashboard tabs to improve layout and overflow handling, ensuring better visibility and usability. - Replaced Typography's Text component with a custom ElipsisText component for improved text overflow management. - Simplified tab selection logic in NavigationTabsContext, enhancing scrolling behavior when selecting tabs. - Introduced a new utility function to scroll tabs into view, improving user experience during navigation.
This commit is contained in:
parent
e7f3e2a6d4
commit
d5096dbba3
@ -3640,6 +3640,7 @@ body.objectKanbanColumnResizing * {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
max-width: 240px;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
margin: 5px 0 0 0;
|
margin: 5px 0 0 0;
|
||||||
padding: 0 10px 0 10px;
|
padding: 0 10px 0 10px;
|
||||||
@ -3843,8 +3844,14 @@ body.objectKanbanColumnResizing * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-label {
|
.dashboard-tabs-label {
|
||||||
max-width: 280px;
|
max-width: 186px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-tabs-label .elipsis-text-wrapper.ant-typography {
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-container[data-sticky-placeholder='true']
|
.dashboard-tab-item-container[data-sticky-placeholder='true']
|
||||||
|
|||||||
@ -7,8 +7,9 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
memo
|
memo
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { Button, Flex, Popover, Typography } from 'antd'
|
import { Button, Flex, Popover } from 'antd'
|
||||||
import DashboardTabPreview from './DashboardTabPreview'
|
import DashboardTabPreview from './DashboardTabPreview'
|
||||||
|
import ElipsisText from './ElipsisText'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import ScrollBox from './ScrollBox'
|
import ScrollBox from './ScrollBox'
|
||||||
import PlusIcon from '../../Icons/PlusIcon'
|
import PlusIcon from '../../Icons/PlusIcon'
|
||||||
@ -23,8 +24,6 @@ import {
|
|||||||
import { getDesktopWindowId } from '../../../electrobun-bridge.js'
|
import { getDesktopWindowId } from '../../../electrobun-bridge.js'
|
||||||
import { hasExternalTabDrag, writeTabDragData } from './tabDrag'
|
import { hasExternalTabDrag, writeTabDragData } from './tabDrag'
|
||||||
|
|
||||||
const { Text } = Typography
|
|
||||||
|
|
||||||
const DashboardTabChrome = () => (
|
const DashboardTabChrome = () => (
|
||||||
<>
|
<>
|
||||||
<span className='dashboard-tab-item-outline-container' aria-hidden='true'>
|
<span className='dashboard-tab-item-outline-container' aria-hidden='true'>
|
||||||
@ -49,9 +48,7 @@ const DashboardTabChrome = () => (
|
|||||||
|
|
||||||
const DashboardTabLabel = ({ tab, onClose }) => (
|
const DashboardTabLabel = ({ tab, onClose }) => (
|
||||||
<Flex align='center' gap={6} className='dashboard-tabs-label'>
|
<Flex align='center' gap={6} className='dashboard-tabs-label'>
|
||||||
<Text ellipsis style={{ maxWidth: 240 }}>
|
<ElipsisText>{tab.title || 'Farm Control'}</ElipsisText>
|
||||||
{tab.title || 'Farm Control'}
|
|
||||||
</Text>
|
|
||||||
<span
|
<span
|
||||||
className='dashboard-tabs-close'
|
className='dashboard-tabs-close'
|
||||||
role='button'
|
role='button'
|
||||||
@ -697,39 +694,10 @@ const DashboardTabs = () => {
|
|||||||
? tabs.findIndex((tab) => tab.id === activeTabId)
|
? tabs.findIndex((tab) => tab.id === activeTabId)
|
||||||
: 0
|
: 0
|
||||||
|
|
||||||
const handleSelectTab = (tabId) => {
|
|
||||||
selectTab(tabId)
|
|
||||||
|
|
||||||
const scrollEl = rootRef.current?.querySelector(
|
|
||||||
'.simplebar-content-wrapper'
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!scrollEl) return
|
|
||||||
|
|
||||||
const tabItem = document.getElementById(`dashboard-tab-item-${tabId}`)
|
|
||||||
|
|
||||||
if (!tabItem) return
|
|
||||||
|
|
||||||
const tabItemRect = tabItem.getBoundingClientRect()
|
|
||||||
const scrollRect = scrollEl.getBoundingClientRect()
|
|
||||||
|
|
||||||
const offset = 50
|
|
||||||
|
|
||||||
// Tab is too close to / off-screen on the left
|
|
||||||
if (tabItemRect.left < scrollRect.left + offset) {
|
|
||||||
scrollEl.scrollLeft -= scrollRect.left - tabItemRect.left + offset
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tab is too close to / off-screen on the right
|
|
||||||
else if (tabItemRect.right > scrollRect.right - offset) {
|
|
||||||
scrollEl.scrollLeft += tabItemRect.right - scrollRect.right + offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabItemProps = {
|
const tabItemProps = {
|
||||||
onDragStart: handleItemDragStart,
|
onDragStart: handleItemDragStart,
|
||||||
onDragEnd: handleItemDragEnd,
|
onDragEnd: handleItemDragEnd,
|
||||||
onClick: handleSelectTab,
|
onClick: selectTab,
|
||||||
onKeyDown: handleKeyDown,
|
onKeyDown: handleKeyDown,
|
||||||
onDragOver: handleItemDragOver,
|
onDragOver: handleItemDragOver,
|
||||||
onDrop: handleItemDrop,
|
onDrop: handleItemDrop,
|
||||||
|
|||||||
@ -394,15 +394,51 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
target: locationToEntry(entry),
|
target: locationToEntry(entry),
|
||||||
from: locationToEntry(locationRef.current),
|
from: locationToEntry(locationRef.current),
|
||||||
previousTabId:
|
previousTabId:
|
||||||
previousTabId === undefined
|
previousTabId === undefined ? activeTabIdRef.current : previousTabId
|
||||||
? activeTabIdRef.current
|
|
||||||
: previousTabId
|
|
||||||
}
|
}
|
||||||
navigate(entryToPath(entry), { replace: true })
|
navigate(entryToPath(entry), { replace: true })
|
||||||
},
|
},
|
||||||
[navigate]
|
[navigate]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const registerTabStripRoot = useCallback((element) => {
|
||||||
|
tabStripRootRef.current = element
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const scrollTabIntoView = useCallback((tabId) => {
|
||||||
|
if (!tabId) return
|
||||||
|
|
||||||
|
const tabs = tabsRef.current
|
||||||
|
const isLastTab = tabs[tabs.length - 1]?.id === tabId
|
||||||
|
const leftInset = 24
|
||||||
|
const rightInset = isLastTab ? 72 : 28
|
||||||
|
|
||||||
|
const run = () => {
|
||||||
|
const root = tabStripRootRef.current
|
||||||
|
const scrollEl = root?.querySelector('.simplebar-content-wrapper')
|
||||||
|
if (!root || !scrollEl) return
|
||||||
|
|
||||||
|
const tabItem = root.querySelector(
|
||||||
|
`#dashboard-tab-item-${CSS.escape(String(tabId))}`
|
||||||
|
)
|
||||||
|
if (!tabItem) return
|
||||||
|
|
||||||
|
const tabRect = tabItem.getBoundingClientRect()
|
||||||
|
const scrollRect = scrollEl.getBoundingClientRect()
|
||||||
|
|
||||||
|
if (tabRect.left < scrollRect.left + leftInset) {
|
||||||
|
scrollEl.scrollLeft += tabRect.left - scrollRect.left - leftInset
|
||||||
|
} else if (tabRect.right > scrollRect.right - rightInset) {
|
||||||
|
scrollEl.scrollLeft += tabRect.right - scrollRect.right + rightInset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
run()
|
||||||
|
requestAnimationFrame(run)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
const selectTab = useCallback(
|
const selectTab = useCallback(
|
||||||
(tabId) => {
|
(tabId) => {
|
||||||
if (!tabId || tabId === activeTabIdRef.current) return
|
if (!tabId || tabId === activeTabIdRef.current) return
|
||||||
@ -414,6 +450,7 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
markForeignLocation(previousTabId)
|
markForeignLocation(previousTabId)
|
||||||
setActiveTabId(tabId)
|
setActiveTabId(tabId)
|
||||||
activeTabIdRef.current = tabId
|
activeTabIdRef.current = tabId
|
||||||
|
scrollTabIntoView(tabId)
|
||||||
|
|
||||||
if (entriesEqual(nextEntry, locationRef.current)) {
|
if (entriesEqual(nextEntry, locationRef.current)) {
|
||||||
return
|
return
|
||||||
@ -421,13 +458,9 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
|
|
||||||
restoreToEntry(nextEntry, { previousTabId })
|
restoreToEntry(nextEntry, { previousTabId })
|
||||||
},
|
},
|
||||||
[markForeignLocation, restoreToEntry]
|
[markForeignLocation, restoreToEntry, scrollTabIntoView]
|
||||||
)
|
)
|
||||||
|
|
||||||
const registerTabStripRoot = useCallback((element) => {
|
|
||||||
tabStripRootRef.current = element
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollTabStripToEndIntervalRef.current) {
|
if (scrollTabStripToEndIntervalRef.current) {
|
||||||
@ -537,10 +570,16 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
if (!entriesEqual(nextEntry, locationRef.current)) {
|
if (!entriesEqual(nextEntry, locationRef.current)) {
|
||||||
restoreToEntry(nextEntry, { previousTabId })
|
restoreToEntry(nextEntry, { previousTabId })
|
||||||
}
|
}
|
||||||
|
scrollTabIntoView(nextActive.id)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
[handleWindowControl, markForeignLocation, restoreToEntry]
|
[
|
||||||
|
handleWindowControl,
|
||||||
|
markForeignLocation,
|
||||||
|
restoreToEntry,
|
||||||
|
scrollTabIntoView
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
const closeTab = useCallback(
|
const closeTab = useCallback(
|
||||||
@ -578,8 +617,9 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
if (!entriesEqual(nextEntry, locationRef.current)) {
|
if (!entriesEqual(nextEntry, locationRef.current)) {
|
||||||
restoreToEntry(nextEntry, { previousTabId })
|
restoreToEntry(nextEntry, { previousTabId })
|
||||||
}
|
}
|
||||||
|
scrollTabIntoView(tab.id)
|
||||||
},
|
},
|
||||||
[markForeignLocation, restoreToEntry]
|
[markForeignLocation, restoreToEntry, scrollTabIntoView]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleTabDragStart = useCallback(
|
const handleTabDragStart = useCallback(
|
||||||
@ -712,26 +752,23 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
return next
|
return next
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setTabPage = useCallback(
|
const setTabPage = useCallback(({ title, modelName, iconKey } = {}) => {
|
||||||
({ title, modelName, iconKey } = {}) => {
|
const activeId = activeTabIdRef.current
|
||||||
const activeId = activeTabIdRef.current
|
if (!activeId) return
|
||||||
if (!activeId) return
|
|
||||||
|
|
||||||
setTabs((current) => {
|
setTabs((current) => {
|
||||||
if (current.length === 0) return current
|
if (current.length === 0) return current
|
||||||
|
|
||||||
let changed = false
|
let changed = false
|
||||||
const next = current.map((tab) => {
|
const next = current.map((tab) => {
|
||||||
if (tab.id !== activeId) return tab
|
if (tab.id !== activeId) return tab
|
||||||
const updated = applyPageMetaToTab(tab, { title, modelName, iconKey })
|
const updated = applyPageMetaToTab(tab, { title, modelName, iconKey })
|
||||||
if (updated !== tab) changed = true
|
if (updated !== tab) changed = true
|
||||||
return updated
|
return updated
|
||||||
})
|
|
||||||
return changed ? next : current
|
|
||||||
})
|
})
|
||||||
},
|
return changed ? next : current
|
||||||
[]
|
})
|
||||||
)
|
}, [])
|
||||||
|
|
||||||
const getTabListState = useCallback((tabId, scope) => {
|
const getTabListState = useCallback((tabId, scope) => {
|
||||||
const tab = tabsRef.current.find((item) => item.id === tabId)
|
const tab = tabsRef.current.find((item) => item.id === tabId)
|
||||||
@ -825,8 +862,7 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
: restoredTabs[0].id
|
: restoredTabs[0].id
|
||||||
setActiveTabId(nextActiveId)
|
setActiveTabId(nextActiveId)
|
||||||
const activeTab =
|
const activeTab =
|
||||||
restoredTabs.find((tab) => tab.id === nextActiveId) ||
|
restoredTabs.find((tab) => tab.id === nextActiveId) || restoredTabs[0]
|
||||||
restoredTabs[0]
|
|
||||||
const entry = getTabCurrentEntry(activeTab)
|
const entry = getTabCurrentEntry(activeTab)
|
||||||
if (!entriesEqual(entry, location)) {
|
if (!entriesEqual(entry, location)) {
|
||||||
restoreToEntry(entry)
|
restoreToEntry(entry)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user