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;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 240px;
|
||||
overflow: visible;
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0 10px 0 10px;
|
||||
@ -3843,8 +3844,14 @@ body.objectKanbanColumnResizing * {
|
||||
}
|
||||
|
||||
.dashboard-tabs-label {
|
||||
max-width: 280px;
|
||||
max-width: 186px;
|
||||
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']
|
||||
|
||||
@ -7,8 +7,9 @@ import {
|
||||
useState,
|
||||
memo
|
||||
} from 'react'
|
||||
import { Button, Flex, Popover, Typography } from 'antd'
|
||||
import { Button, Flex, Popover } from 'antd'
|
||||
import DashboardTabPreview from './DashboardTabPreview'
|
||||
import ElipsisText from './ElipsisText'
|
||||
import classNames from 'classnames'
|
||||
import ScrollBox from './ScrollBox'
|
||||
import PlusIcon from '../../Icons/PlusIcon'
|
||||
@ -23,8 +24,6 @@ import {
|
||||
import { getDesktopWindowId } from '../../../electrobun-bridge.js'
|
||||
import { hasExternalTabDrag, writeTabDragData } from './tabDrag'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
const DashboardTabChrome = () => (
|
||||
<>
|
||||
<span className='dashboard-tab-item-outline-container' aria-hidden='true'>
|
||||
@ -49,9 +48,7 @@ const DashboardTabChrome = () => (
|
||||
|
||||
const DashboardTabLabel = ({ tab, onClose }) => (
|
||||
<Flex align='center' gap={6} className='dashboard-tabs-label'>
|
||||
<Text ellipsis style={{ maxWidth: 240 }}>
|
||||
{tab.title || 'Farm Control'}
|
||||
</Text>
|
||||
<ElipsisText>{tab.title || 'Farm Control'}</ElipsisText>
|
||||
<span
|
||||
className='dashboard-tabs-close'
|
||||
role='button'
|
||||
@ -697,39 +694,10 @@ const DashboardTabs = () => {
|
||||
? tabs.findIndex((tab) => tab.id === activeTabId)
|
||||
: 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 = {
|
||||
onDragStart: handleItemDragStart,
|
||||
onDragEnd: handleItemDragEnd,
|
||||
onClick: handleSelectTab,
|
||||
onClick: selectTab,
|
||||
onKeyDown: handleKeyDown,
|
||||
onDragOver: handleItemDragOver,
|
||||
onDrop: handleItemDrop,
|
||||
|
||||
@ -394,15 +394,51 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
target: locationToEntry(entry),
|
||||
from: locationToEntry(locationRef.current),
|
||||
previousTabId:
|
||||
previousTabId === undefined
|
||||
? activeTabIdRef.current
|
||||
: previousTabId
|
||||
previousTabId === undefined ? activeTabIdRef.current : previousTabId
|
||||
}
|
||||
navigate(entryToPath(entry), { replace: true })
|
||||
},
|
||||
[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(
|
||||
(tabId) => {
|
||||
if (!tabId || tabId === activeTabIdRef.current) return
|
||||
@ -414,6 +450,7 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
markForeignLocation(previousTabId)
|
||||
setActiveTabId(tabId)
|
||||
activeTabIdRef.current = tabId
|
||||
scrollTabIntoView(tabId)
|
||||
|
||||
if (entriesEqual(nextEntry, locationRef.current)) {
|
||||
return
|
||||
@ -421,13 +458,9 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
|
||||
restoreToEntry(nextEntry, { previousTabId })
|
||||
},
|
||||
[markForeignLocation, restoreToEntry]
|
||||
[markForeignLocation, restoreToEntry, scrollTabIntoView]
|
||||
)
|
||||
|
||||
const registerTabStripRoot = useCallback((element) => {
|
||||
tabStripRootRef.current = element
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (scrollTabStripToEndIntervalRef.current) {
|
||||
@ -537,10 +570,16 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
if (!entriesEqual(nextEntry, locationRef.current)) {
|
||||
restoreToEntry(nextEntry, { previousTabId })
|
||||
}
|
||||
scrollTabIntoView(nextActive.id)
|
||||
}
|
||||
return true
|
||||
},
|
||||
[handleWindowControl, markForeignLocation, restoreToEntry]
|
||||
[
|
||||
handleWindowControl,
|
||||
markForeignLocation,
|
||||
restoreToEntry,
|
||||
scrollTabIntoView
|
||||
]
|
||||
)
|
||||
|
||||
const closeTab = useCallback(
|
||||
@ -578,8 +617,9 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
if (!entriesEqual(nextEntry, locationRef.current)) {
|
||||
restoreToEntry(nextEntry, { previousTabId })
|
||||
}
|
||||
scrollTabIntoView(tab.id)
|
||||
},
|
||||
[markForeignLocation, restoreToEntry]
|
||||
[markForeignLocation, restoreToEntry, scrollTabIntoView]
|
||||
)
|
||||
|
||||
const handleTabDragStart = useCallback(
|
||||
@ -712,26 +752,23 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
return next
|
||||
}, [])
|
||||
|
||||
const setTabPage = useCallback(
|
||||
({ title, modelName, iconKey } = {}) => {
|
||||
const activeId = activeTabIdRef.current
|
||||
if (!activeId) return
|
||||
const setTabPage = useCallback(({ title, modelName, iconKey } = {}) => {
|
||||
const activeId = activeTabIdRef.current
|
||||
if (!activeId) return
|
||||
|
||||
setTabs((current) => {
|
||||
if (current.length === 0) return current
|
||||
setTabs((current) => {
|
||||
if (current.length === 0) return current
|
||||
|
||||
let changed = false
|
||||
const next = current.map((tab) => {
|
||||
if (tab.id !== activeId) return tab
|
||||
const updated = applyPageMetaToTab(tab, { title, modelName, iconKey })
|
||||
if (updated !== tab) changed = true
|
||||
return updated
|
||||
})
|
||||
return changed ? next : current
|
||||
let changed = false
|
||||
const next = current.map((tab) => {
|
||||
if (tab.id !== activeId) return tab
|
||||
const updated = applyPageMetaToTab(tab, { title, modelName, iconKey })
|
||||
if (updated !== tab) changed = true
|
||||
return updated
|
||||
})
|
||||
},
|
||||
[]
|
||||
)
|
||||
return changed ? next : current
|
||||
})
|
||||
}, [])
|
||||
|
||||
const getTabListState = useCallback((tabId, scope) => {
|
||||
const tab = tabsRef.current.find((item) => item.id === tabId)
|
||||
@ -825,8 +862,7 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
: restoredTabs[0].id
|
||||
setActiveTabId(nextActiveId)
|
||||
const activeTab =
|
||||
restoredTabs.find((tab) => tab.id === nextActiveId) ||
|
||||
restoredTabs[0]
|
||||
restoredTabs.find((tab) => tab.id === nextActiveId) || restoredTabs[0]
|
||||
const entry = getTabCurrentEntry(activeTab)
|
||||
if (!entriesEqual(entry, location)) {
|
||||
restoreToEntry(entry)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user