Refactor Dashboard Tabs and Enhance CSS Styles
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:
Tom Butcher 2026-09-21 01:58:03 +01:00
parent e7f3e2a6d4
commit d5096dbba3
3 changed files with 77 additions and 66 deletions

View File

@ -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']

View File

@ -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,

View File

@ -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,8 +752,7 @@ export const NavigationTabsProvider = ({ children }) => {
return next
}, [])
const setTabPage = useCallback(
({ title, modelName, iconKey } = {}) => {
const setTabPage = useCallback(({ title, modelName, iconKey } = {}) => {
const activeId = activeTabIdRef.current
if (!activeId) return
@ -729,9 +768,7 @@ export const NavigationTabsProvider = ({ children }) => {
})
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)