Tabs: Reduce active border from 4 px to 2px (#101888)
* Tabs: Reduce active border from 4 to 2px * css fixes
This commit is contained in:
@@ -43,9 +43,6 @@ export interface ThemeComponents {
|
||||
sidemenu: {
|
||||
width: number;
|
||||
};
|
||||
menuTabs: {
|
||||
height: number;
|
||||
};
|
||||
horizontalDrawer: {
|
||||
defaultHeight: number;
|
||||
};
|
||||
@@ -96,6 +93,7 @@ export function createComponents(colors: ThemeColors, shadows: ThemeShadows): Th
|
||||
sidemenu: {
|
||||
width: 57,
|
||||
},
|
||||
// @ts-expect-error (added here to not crash plugins that might use it)
|
||||
menuTabs: {
|
||||
height: 5,
|
||||
},
|
||||
|
||||
@@ -6,8 +6,9 @@ import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { IconButton } from '../../components/IconButton/IconButton';
|
||||
import { TabsBar, Tab, TabContent } from '../../components/Tabs';
|
||||
import { useStyles2, useTheme2 } from '../../themes';
|
||||
import { useStyles2 } from '../../themes';
|
||||
import { IconName } from '../../types/icon';
|
||||
import { Box } from '../Layout/Box/Box';
|
||||
import { ScrollContainer } from '../ScrollContainer/ScrollContainer';
|
||||
|
||||
export interface TabConfig {
|
||||
@@ -28,14 +29,11 @@ export interface TabbedContainerProps {
|
||||
export function TabbedContainer({ tabs, defaultTab, closeIconTooltip, onClose, testId }: TabbedContainerProps) {
|
||||
const [activeTab, setActiveTab] = useState(tabs.some((tab) => tab.value === defaultTab) ? defaultTab : tabs[0].value);
|
||||
const styles = useStyles2(getStyles);
|
||||
const theme = useTheme2();
|
||||
|
||||
const onSelectTab = (item: SelectableValue<string>) => {
|
||||
setActiveTab(item.value!);
|
||||
};
|
||||
|
||||
const autoHeight = `calc(100% - (${theme.spacing(theme.components.menuTabs.height)} + ${theme.spacing(1)}))`;
|
||||
|
||||
return (
|
||||
<div className={styles.container} data-testid={testId}>
|
||||
<TabsBar className={styles.tabs}>
|
||||
@@ -48,9 +46,11 @@ export function TabbedContainer({ tabs, defaultTab, closeIconTooltip, onClose, t
|
||||
icon={t.icon}
|
||||
/>
|
||||
))}
|
||||
<IconButton className={styles.close} onClick={onClose} name="times" tooltip={closeIconTooltip ?? 'Close'} />
|
||||
<Box grow={1} display="flex" justifyContent="flex-end" paddingRight={1}>
|
||||
<IconButton size="lg" onClick={onClose} name="times" tooltip={closeIconTooltip ?? 'Close'} />
|
||||
</Box>
|
||||
</TabsBar>
|
||||
<ScrollContainer height={autoHeight}>
|
||||
<ScrollContainer>
|
||||
<TabContent className={styles.tabContent}>{tabs.find((t) => t.value === activeTab)?.content}</TabContent>
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
@@ -60,21 +60,17 @@ export function TabbedContainer({ tabs, defaultTab, closeIconTooltip, onClose, t
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
container: css({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: '1 1 0',
|
||||
minHeight: 0,
|
||||
}),
|
||||
tabContent: css({
|
||||
padding: theme.spacing(2),
|
||||
backgroundColor: theme.colors.background.primary,
|
||||
height: `100%`,
|
||||
}),
|
||||
close: css({
|
||||
position: 'absolute',
|
||||
right: '16px',
|
||||
top: '5px',
|
||||
cursor: 'pointer',
|
||||
fontSize: theme.typography.size.lg,
|
||||
}),
|
||||
tabs: css({
|
||||
paddingTop: theme.spacing(1),
|
||||
paddingTop: theme.spacing(0.5),
|
||||
borderColor: theme.colors.border.weak,
|
||||
ul: {
|
||||
marginLeft: theme.spacing(2),
|
||||
|
||||
@@ -92,11 +92,11 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
whiteSpace: 'nowrap',
|
||||
padding: theme.spacing(0.5),
|
||||
padding: theme.spacing(0, 0.5),
|
||||
}),
|
||||
link: css({
|
||||
color: theme.colors.text.secondary,
|
||||
padding: theme.spacing(1, 1.5, 0.5),
|
||||
padding: theme.spacing(1, 1.5, 1),
|
||||
borderRadius: theme.shape.radius.default,
|
||||
|
||||
display: 'block',
|
||||
@@ -114,7 +114,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '4px',
|
||||
height: '2px',
|
||||
borderRadius: theme.shape.radius.default,
|
||||
bottom: 0,
|
||||
},
|
||||
|
||||
@@ -36,8 +36,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
tabs: css({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
height: theme.spacing(theme.components.menuTabs.height),
|
||||
alignItems: 'stretch',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { cx } from '@emotion/css';
|
||||
import { useLocation } from 'react-router';
|
||||
|
||||
import { GrafanaTheme2, locationUtil, textUtil } from '@grafana/data';
|
||||
import { locationUtil, textUtil } from '@grafana/data';
|
||||
import { SceneComponentProps, sceneGraph } from '@grafana/scenes';
|
||||
import { clearButtonStyles, useElementSelection, useStyles2 } from '@grafana/ui';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { getFocusStyles } from '@grafana/ui/src/themes/mixins';
|
||||
import { Tab, useElementSelection } from '@grafana/ui';
|
||||
|
||||
import { TabItem } from './TabItem';
|
||||
|
||||
@@ -19,87 +17,19 @@ export function TabItemRenderer({ model }: SceneComponentProps<TabItem>) {
|
||||
const isActive = myIndex === currentTabIndex;
|
||||
const location = useLocation();
|
||||
const href = textUtil.sanitize(locationUtil.getUrlForPartial(location, { tab: myIndex }));
|
||||
const styles = useStyles2(getStyles);
|
||||
const clearStyles = useStyles2(clearButtonStyles);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cx(
|
||||
styles.container,
|
||||
isSelected && 'dashboard-selected-element',
|
||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||
)}
|
||||
role="presentation"
|
||||
>
|
||||
<a
|
||||
href={href}
|
||||
className={cx(clearStyles, styles.label, isActive ? styles.labelActive : styles.labelNotActive)}
|
||||
role="tab"
|
||||
aria-selected={isActive}
|
||||
onPointerDown={onSelect}
|
||||
>
|
||||
{titleInterpolated}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
<Tab
|
||||
className={cx(
|
||||
isSelected && 'dashboard-selected-element',
|
||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||
)}
|
||||
active={isActive}
|
||||
role="presentation"
|
||||
href={href}
|
||||
aria-selected={isActive}
|
||||
onPointerDown={onSelect}
|
||||
label={titleInterpolated}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function getStyles(theme: GrafanaTheme2) {
|
||||
return {
|
||||
container: css({
|
||||
listStyle: 'none',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
whiteSpace: 'nowrap',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
checkboxWrapper: css({
|
||||
paddingLeft: theme.spacing(1),
|
||||
}),
|
||||
label: css({
|
||||
color: theme.colors.text.secondary,
|
||||
padding: theme.spacing(1, 2, 0.5),
|
||||
borderRadius: theme.shape.radius.default,
|
||||
userSelect: 'none',
|
||||
|
||||
display: 'block',
|
||||
height: '100%',
|
||||
|
||||
svg: {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
|
||||
'&:focus-visible': getFocusStyles(theme),
|
||||
|
||||
'&::before': {
|
||||
display: 'block',
|
||||
content: '" "',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '4px',
|
||||
borderRadius: theme.shape.radius.default,
|
||||
bottom: 0,
|
||||
},
|
||||
}),
|
||||
labelNotActive: css({
|
||||
'&:hover, &:focus': {
|
||||
color: theme.colors.text.primary,
|
||||
|
||||
'&::before': {
|
||||
backgroundColor: theme.colors.action.hover,
|
||||
},
|
||||
},
|
||||
}),
|
||||
labelActive: css({
|
||||
color: theme.colors.text.primary,
|
||||
overflow: 'hidden',
|
||||
|
||||
'&::before': {
|
||||
backgroundImage: theme.colors.gradients.brandHorizontal,
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,12 +60,13 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
overflowX: 'auto',
|
||||
overflowY: 'hidden',
|
||||
paddingInline: theme.spacing(0.125),
|
||||
paddingTop: '1px',
|
||||
}),
|
||||
tabContentContainer: css({
|
||||
backgroundColor: 'transparent',
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
padding: '2px 2px 0 2px',
|
||||
paddingTop: theme.spacing(1),
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user