Enhance Dashboard Styles and Navigation with Improved Layout Adjustments
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 new CSS styles for dashboard menu container and tabs, improving visual alignment and spacing. - Introduced logic to manage scroll edge fades for better user experience during tab navigation. - Adjusted padding and margin properties for dashboard elements to enhance overall aesthetics and usability. - Reformatted component code for improved readability and consistency.
This commit is contained in:
parent
abe183c82a
commit
0b4b8128de
@ -185,6 +185,10 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-menu-container-navigation-labels:after {
|
||||||
|
right: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
.electron-navigation-leading,
|
.electron-navigation-leading,
|
||||||
.electron-navigation-trailing {
|
.electron-navigation-trailing {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
@ -3481,27 +3485,43 @@ body.objectKanbanColumnResizing * {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-tabs-wrap .simplebar-content-wrapper {
|
||||||
|
overscroll-behavior-x: none;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap .simplebar-mask {
|
.dashboard-tabs-wrap .simplebar-mask {
|
||||||
--tab-mask-left: 0px;
|
--tab-mask-left: 4px;
|
||||||
--tab-mask-right: 0px;
|
--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(
|
||||||
to right,
|
to right,
|
||||||
transparent var(--tab-mask-left),
|
transparent var(--tab-mask-left),
|
||||||
#000 calc(var(--tab-mask-left) + var(--tab-mask-fade)),
|
#000 calc(var(--tab-mask-left) + var(--tab-mask-fade-left)),
|
||||||
#000 calc(100% - var(--tab-mask-right) - var(--tab-mask-fade)),
|
#000 calc(100% - var(--tab-mask-right) - var(--tab-mask-fade-right)),
|
||||||
transparent calc(100% - var(--tab-mask-right))
|
transparent calc(100% - var(--tab-mask-right))
|
||||||
);
|
);
|
||||||
mask-image: linear-gradient(
|
mask-image: linear-gradient(
|
||||||
to right,
|
to right,
|
||||||
transparent var(--tab-mask-left),
|
transparent var(--tab-mask-left),
|
||||||
#000 calc(var(--tab-mask-left) + var(--tab-mask-fade)),
|
#000 calc(var(--tab-mask-left) + var(--tab-mask-fade-left)),
|
||||||
#000 calc(100% - var(--tab-mask-right) - var(--tab-mask-fade)),
|
#000 calc(100% - var(--tab-mask-right) - var(--tab-mask-fade-right)),
|
||||||
transparent calc(100% - var(--tab-mask-right))
|
transparent calc(100% - var(--tab-mask-right))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-tabs[data-at-start] .dashboard-tabs-wrap .simplebar-mask {
|
||||||
|
--tab-mask-left: 0px;
|
||||||
|
--tab-mask-fade-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-tabs[data-at-end] .dashboard-tabs-wrap .simplebar-mask {
|
||||||
|
--tab-mask-right: 0px;
|
||||||
|
--tab-mask-fade-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-tabs-wrap::before,
|
.dashboard-tabs-wrap::before,
|
||||||
.dashboard-tabs-wrap::after {
|
.dashboard-tabs-wrap::after {
|
||||||
content: '';
|
content: '';
|
||||||
@ -3572,7 +3592,7 @@ body.objectKanbanColumnResizing * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-container:first-child:before {
|
.dashboard-tab-item-container:first-child:before {
|
||||||
left: -14px;
|
left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-container:last-child:before {
|
.dashboard-tab-item-container:last-child:before {
|
||||||
@ -3662,14 +3682,25 @@ body.objectKanbanColumnResizing * {
|
|||||||
border-radius: 12px 12px 0 0;
|
border-radius: 12px 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-tab-item-active:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 21px;
|
||||||
|
border-radius: 11px 11px 0 0;
|
||||||
|
z-index: -2;
|
||||||
|
background: var(--color-layout-background);
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-active:after {
|
.dashboard-tab-item-active:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1px;
|
top: 14px;
|
||||||
left: 1px;
|
left: 1px;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
bottom: -1px;
|
bottom: -1px;
|
||||||
border-radius: 9px 9px 0 0;
|
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
background: var(--color-layout-background);
|
background: var(--color-layout-background);
|
||||||
}
|
}
|
||||||
@ -3699,6 +3730,10 @@ body.objectKanbanColumnResizing * {
|
|||||||
--tab-corner-center: calc(
|
--tab-corner-center: calc(
|
||||||
var(--tab-corner-size) - var(--tab-corner-inset) - var(--tab-corner-radius)
|
var(--tab-corner-size) - var(--tab-corner-inset) - var(--tab-corner-radius)
|
||||||
);
|
);
|
||||||
|
--tab-fill-nudge-x: 3px;
|
||||||
|
--tab-fill-nudge-y: 4px;
|
||||||
|
--tab-fill-circle-x: calc(var(--tab-corner-center) + var(--tab-fill-nudge-x));
|
||||||
|
--tab-fill-circle-y: calc(var(--tab-corner-size) - var(--tab-corner-radius));
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1px;
|
bottom: -1px;
|
||||||
width: var(--tab-corner-size);
|
width: var(--tab-corner-size);
|
||||||
@ -3718,35 +3753,39 @@ body.objectKanbanColumnResizing * {
|
|||||||
|
|
||||||
.dashboard-tab-item-corner-fill {
|
.dashboard-tab-item-corner-fill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
bottom: calc(-1 * var(--tab-fill-nudge-y));
|
||||||
background: var(--color-layout-background);
|
background: var(--color-layout-background);
|
||||||
-webkit-mask-repeat: no-repeat;
|
-webkit-mask-repeat: no-repeat;
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-corner-left .dashboard-tab-item-corner-fill {
|
.dashboard-tab-item-corner-left .dashboard-tab-item-corner-fill {
|
||||||
|
left: calc(-1 * var(--tab-fill-nudge-x));
|
||||||
-webkit-mask-image: radial-gradient(
|
-webkit-mask-image: radial-gradient(
|
||||||
circle at var(--tab-corner-center) var(--tab-corner-center),
|
circle at var(--tab-fill-circle-x) var(--tab-fill-circle-y),
|
||||||
transparent calc(var(--tab-corner-radius) - 0.5px),
|
transparent var(--tab-corner-radius),
|
||||||
#000 calc(var(--tab-corner-radius) - 0.5px)
|
#000 var(--tab-corner-radius)
|
||||||
);
|
);
|
||||||
mask-image: radial-gradient(
|
mask-image: radial-gradient(
|
||||||
circle at var(--tab-corner-center) var(--tab-corner-center),
|
circle at var(--tab-fill-circle-x) var(--tab-fill-circle-y),
|
||||||
transparent calc(var(--tab-corner-radius) - 0.5px),
|
transparent var(--tab-corner-radius),
|
||||||
#000 calc(var(--tab-corner-radius) - 0.5px)
|
#000 var(--tab-corner-radius)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tab-item-corner-right .dashboard-tab-item-corner-fill {
|
.dashboard-tab-item-corner-right .dashboard-tab-item-corner-fill {
|
||||||
|
right: calc(-1 * var(--tab-fill-nudge-x));
|
||||||
-webkit-mask-image: radial-gradient(
|
-webkit-mask-image: radial-gradient(
|
||||||
circle at calc(100% - var(--tab-corner-center)) var(--tab-corner-center),
|
circle at calc(100% - var(--tab-fill-circle-x)) var(--tab-fill-circle-y),
|
||||||
transparent calc(var(--tab-corner-radius) - 0.5px),
|
transparent var(--tab-corner-radius),
|
||||||
#000 calc(var(--tab-corner-radius) - 0.5px)
|
#000 var(--tab-corner-radius)
|
||||||
);
|
);
|
||||||
mask-image: radial-gradient(
|
mask-image: radial-gradient(
|
||||||
circle at calc(100% - var(--tab-corner-center)) var(--tab-corner-center),
|
circle at calc(100% - var(--tab-fill-circle-x)) var(--tab-fill-circle-y),
|
||||||
transparent calc(var(--tab-corner-radius) - 0.5px),
|
transparent var(--tab-corner-radius),
|
||||||
#000 calc(var(--tab-corner-radius) - 0.5px)
|
#000 var(--tab-corner-radius)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3797,7 +3836,9 @@ body.objectKanbanColumnResizing * {
|
|||||||
.dashboard-tabs[data-sticky-edge] .dashboard-tab-item-container:before,
|
.dashboard-tabs[data-sticky-edge] .dashboard-tab-item-container:before,
|
||||||
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-add-button-container:before,
|
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-add-button-container:before,
|
||||||
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-wrap::before,
|
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-wrap::before,
|
||||||
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-wrap::after {
|
.dashboard-tabs[data-sticky-edge] .dashboard-tabs-wrap::after,
|
||||||
|
.dashboard-tabs[data-at-start] .dashboard-tabs-wrap::before,
|
||||||
|
.dashboard-tabs[data-at-end] .dashboard-tabs-wrap::after {
|
||||||
content: none;
|
content: none;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -3897,9 +3938,10 @@ body.objectKanbanColumnResizing * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-add-button {
|
.dashboard-tabs-add-button {
|
||||||
padding-inline: 4px;
|
padding-inline: 5px;
|
||||||
min-width: 20px;
|
min-width: 22px;
|
||||||
margin-top: 2px;
|
margin-top: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-add-button-container {
|
.dashboard-tabs-add-button-container {
|
||||||
@ -3911,7 +3953,7 @@ body.objectKanbanColumnResizing * {
|
|||||||
.dashboard-tabs-add-button-container:before {
|
.dashboard-tabs-add-button-container:before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 12px;
|
left: 15px;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
border-bottom: 1px solid var(--color-header-border);
|
border-bottom: 1px solid var(--color-header-border);
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
// DashboardNavigation.js
|
// DashboardNavigation.js
|
||||||
import { useContext, useEffect, useState, useMemo, useCallback, memo } from 'react'
|
import {
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useMemo,
|
||||||
|
useCallback,
|
||||||
|
memo
|
||||||
|
} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
@ -12,6 +19,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Popover
|
Popover
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
|
import classNames from 'classnames'
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { SpotlightContext } from '../context/SpotlightContext'
|
import { SpotlightContext } from '../context/SpotlightContext'
|
||||||
import { ApiServerContext } from '../context/ApiServerContext'
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
@ -89,7 +97,11 @@ const NAV_OVERFLOW_BUTTON_STYLE = { marginBottom: '4px' }
|
|||||||
const navigationFadeClass = (visible) =>
|
const navigationFadeClass = (visible) =>
|
||||||
`dashboard-navigation-fade${visible ? '' : ' dashboard-navigation-fade-hidden'}`
|
`dashboard-navigation-fade${visible ? '' : ' dashboard-navigation-fade-hidden'}`
|
||||||
|
|
||||||
const NavigationFade = memo(function NavigationFade({ visible, children, style }) {
|
const NavigationFade = memo(function NavigationFade({
|
||||||
|
visible,
|
||||||
|
children,
|
||||||
|
style
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={navigationFadeClass(visible)}
|
className={navigationFadeClass(visible)}
|
||||||
@ -213,27 +225,33 @@ DashboardNavigationTrailingItems.propTypes = {
|
|||||||
onCheckUpdates: PropTypes.func
|
onCheckUpdates: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
const DashboardElectronCenterItems = memo(function DashboardElectronCenterItems({
|
const DashboardElectronCenterItems = memo(
|
||||||
menu,
|
function DashboardElectronCenterItems({ menu, showNavigationLabels }) {
|
||||||
showNavigationLabels
|
return (
|
||||||
}) {
|
<>
|
||||||
return (
|
<div
|
||||||
<>
|
className={classNames(
|
||||||
<div className='dashboard-menu-container'>{menu}</div>
|
'dashboard-menu-container',
|
||||||
<Divider
|
showNavigationLabels && 'dashboard-menu-container-navigation-labels'
|
||||||
type='vertical'
|
)}
|
||||||
style={
|
>
|
||||||
showNavigationLabels
|
{menu}
|
||||||
? NAV_ELECTRON_DIVIDER_STYLE_WITH_LABELS
|
</div>
|
||||||
: NAV_ELECTRON_DIVIDER_STYLE
|
<Divider
|
||||||
}
|
type='vertical'
|
||||||
/>
|
style={
|
||||||
<div style={NAV_ELECTRON_TABS_STYLE}>
|
showNavigationLabels
|
||||||
<DashboardTabs />
|
? NAV_ELECTRON_DIVIDER_STYLE_WITH_LABELS
|
||||||
</div>
|
: NAV_ELECTRON_DIVIDER_STYLE
|
||||||
</>
|
}
|
||||||
)
|
/>
|
||||||
})
|
<div style={NAV_ELECTRON_TABS_STYLE}>
|
||||||
|
<DashboardTabs />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
DashboardElectronCenterItems.propTypes = {
|
DashboardElectronCenterItems.propTypes = {
|
||||||
menu: PropTypes.node,
|
menu: PropTypes.node,
|
||||||
@ -520,7 +538,11 @@ const DashboardNavigation = () => {
|
|||||||
}, [checkForUpdates])
|
}, [checkForUpdates])
|
||||||
const overflowedIndicator = useMemo(
|
const overflowedIndicator = useMemo(
|
||||||
() => (
|
() => (
|
||||||
<Button type='text' icon={<MenuIcon />} style={NAV_OVERFLOW_BUTTON_STYLE} />
|
<Button
|
||||||
|
type='text'
|
||||||
|
icon={<MenuIcon />}
|
||||||
|
style={NAV_OVERFLOW_BUTTON_STYLE}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -191,6 +191,22 @@ const setSimplebarMaskInset = (maskEl, edge, inset) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setScrollEdgeFades = (root, scrollEl) => {
|
||||||
|
if (!root) return
|
||||||
|
if (!scrollEl) {
|
||||||
|
root.dataset.atStart = ''
|
||||||
|
root.dataset.atEnd = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const atStart = scrollEl.scrollLeft <= 1
|
||||||
|
const atEnd =
|
||||||
|
scrollEl.scrollLeft + scrollEl.clientWidth >= scrollEl.scrollWidth - 1
|
||||||
|
if (atStart) root.dataset.atStart = ''
|
||||||
|
else delete root.dataset.atStart
|
||||||
|
if (atEnd) root.dataset.atEnd = ''
|
||||||
|
else delete root.dataset.atEnd
|
||||||
|
}
|
||||||
|
|
||||||
const setStickyStripLine = (root, lineEl, edge, lineInset) => {
|
const setStickyStripLine = (root, lineEl, edge, lineInset) => {
|
||||||
if (root) {
|
if (root) {
|
||||||
if (!edge) delete root.dataset.stickyEdge
|
if (!edge) delete root.dataset.stickyEdge
|
||||||
@ -244,6 +260,7 @@ const bindActiveTabStickyScroll = (scrollEl, list, cloneEl, root, lineEl) => {
|
|||||||
state.updating = true
|
state.updating = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setScrollEdgeFades(root, scrollEl)
|
||||||
const container = list.querySelector(
|
const container = list.querySelector(
|
||||||
'.dashboard-tab-item-container-active'
|
'.dashboard-tab-item-container-active'
|
||||||
)
|
)
|
||||||
@ -355,6 +372,7 @@ const bindActiveTabStickyScroll = (scrollEl, list, cloneEl, root, lineEl) => {
|
|||||||
const observer = new ResizeObserver(scheduleUpdate)
|
const observer = new ResizeObserver(scheduleUpdate)
|
||||||
observer.observe(scrollEl)
|
observer.observe(scrollEl)
|
||||||
if (wrapperEl !== scrollEl) observer.observe(wrapperEl)
|
if (wrapperEl !== scrollEl) observer.observe(wrapperEl)
|
||||||
|
observer.observe(list)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
scrollEl.removeEventListener('scroll', scheduleUpdate)
|
scrollEl.removeEventListener('scroll', scheduleUpdate)
|
||||||
@ -363,6 +381,8 @@ const bindActiveTabStickyScroll = (scrollEl, list, cloneEl, root, lineEl) => {
|
|||||||
if (frame) window.cancelAnimationFrame(frame)
|
if (frame) window.cancelAnimationFrame(frame)
|
||||||
setOriginalStickyState(state.activeEl, false)
|
setOriginalStickyState(state.activeEl, false)
|
||||||
clearStickyVisuals()
|
clearStickyVisuals()
|
||||||
|
delete root.dataset.atStart
|
||||||
|
delete root.dataset.atEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +633,7 @@ const DashboardTabs = () => {
|
|||||||
onDrop={handleStripDrop}
|
onDrop={handleStripDrop}
|
||||||
>
|
>
|
||||||
<ScrollBox className='dashboard-tabs-wrap' horizontal>
|
<ScrollBox className='dashboard-tabs-wrap' horizontal>
|
||||||
<Flex align='flex-start' gap={8} className='dashboard-tabs-inner'>
|
<Flex align='flex-start' gap={5} className='dashboard-tabs-inner'>
|
||||||
<div
|
<div
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
className={classNames('dashboard-tabs-list', {
|
className={classNames('dashboard-tabs-list', {
|
||||||
@ -660,7 +680,6 @@ const DashboardTabs = () => {
|
|||||||
<div className='dashboard-tabs-add-button-container'>
|
<div className='dashboard-tabs-add-button-container'>
|
||||||
<Button
|
<Button
|
||||||
type='text'
|
type='text'
|
||||||
size='small'
|
|
||||||
className='dashboard-tabs-add-button electrobun-webkit-app-region-no-drag'
|
className='dashboard-tabs-add-button electrobun-webkit-app-region-no-drag'
|
||||||
onClick={addTab}
|
onClick={addTab}
|
||||||
icon={<PlusIcon style={{ fontSize: 14, marginTop: 3 }} />}
|
icon={<PlusIcon style={{ fontSize: 14, marginTop: 3 }} />}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user