feat(ui): sidePanel expandedWidth (#3728)

This commit is contained in:
Sofien-Sellami 2024-01-08 19:59:20 +01:00 committed by GitHub
parent 3d98548072
commit 61bf22c6f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 33 deletions

View File

@ -8,6 +8,7 @@ export type SidePanelWithServicesProps = {
className: string; className: string;
activeTabIndex: number; activeTabIndex: number;
tabs: any; tabs: any;
expandedWidth?: number;
}; };
const SidePanelWithServices = ({ const SidePanelWithServices = ({
@ -16,7 +17,8 @@ const SidePanelWithServices = ({
className, className,
activeTabIndex: activeTabIndexProp, activeTabIndex: activeTabIndexProp,
tabs, tabs,
}) => { expandedWidth,
}: SidePanelWithServicesProps) => {
const panelService: PanelService = servicesManager?.services?.panelService; const panelService: PanelService = servicesManager?.services?.panelService;
// Tracks whether this SidePanel has been opened at least once since this SidePanel was inserted into the DOM. // Tracks whether this SidePanel has been opened at least once since this SidePanel was inserted into the DOM.
@ -53,6 +55,7 @@ const SidePanelWithServices = ({
onOpen={() => { onOpen={() => {
setHasBeenOpened(true); setHasBeenOpened(true);
}} }}
expandedWidth={expandedWidth}
></SidePanel> ></SidePanel>
); );
}; };

View File

@ -1,39 +1,26 @@
import classnames from 'classnames'; import classnames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { CSSProperties, useCallback, useEffect, useState } from 'react'; import React, { CSSProperties, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Icon from '../Icon'; import Icon from '../Icon';
import Tooltip from '../Tooltip'; import Tooltip from '../Tooltip';
type StyleMap = {
open: {
left: { marginLeft: string };
right: { marginRight: string };
};
closed: {
left: { marginLeft: string };
right: { marginRight: string };
};
};
const borderSize = 4; const borderSize = 4;
const expandedWidth = 248;
const collapsedWidth = 25; const collapsedWidth = 25;
const closeIconWidth = 30; const closeIconWidth = 30;
const gridHorizontalPadding = 10; const gridHorizontalPadding = 10;
const tabSpacerWidth = 2; const tabSpacerWidth = 2;
const gridAvailableWidth = expandedWidth - closeIconWidth - gridHorizontalPadding;
const baseStyle = {
maxWidth: `${expandedWidth}px`,
width: `${expandedWidth}px`,
// To align the top of the side panel with the top of the viewport grid, use position relative and offset the
// top by the same top offset as the viewport grid. Also adjust the height so that there is no overflow.
position: 'relative',
top: '0.2%',
height: '99.8%',
};
const collapsedHideWidth = expandedWidth - collapsedWidth - borderSize;
const styleMap = {
open: {
left: { marginLeft: '0px' },
right: { marginRight: '0px' },
},
closed: {
left: { marginLeft: `-${collapsedHideWidth}px` },
right: { marginRight: `-${collapsedHideWidth}px` },
},
};
const baseClasses = const baseClasses =
'transition-all duration-300 ease-in-out bg-black border-black justify-start box-content flex flex-col'; 'transition-all duration-300 ease-in-out bg-black border-black justify-start box-content flex flex-col';
@ -62,7 +49,7 @@ const getTabWidth = (numTabs: number) => {
} }
}; };
const getGridWidth = (numTabs: number) => { const getGridWidth = (numTabs: number, gridAvailableWidth: number) => {
const spacersWidth = (numTabs - 1) * tabSpacerWidth; const spacersWidth = (numTabs - 1) * tabSpacerWidth;
const tabsWidth = getTabWidth(numTabs) * numTabs; const tabsWidth = getTabWidth(numTabs) * numTabs;
@ -73,14 +60,13 @@ const getGridWidth = (numTabs: number) => {
return gridAvailableWidth; return gridAvailableWidth;
}; };
const getNumGridColumns = (numTabs: number) => { const getNumGridColumns = (numTabs: number, gridWidth: number) => {
if (numTabs === 1) { if (numTabs === 1) {
return 1; return 1;
} }
// Start by calculating the number of tabs assuming each tab was accompanied by a spacer. // Start by calculating the number of tabs assuming each tab was accompanied by a spacer.
const tabWidth = getTabWidth(numTabs); const tabWidth = getTabWidth(numTabs);
const gridWidth = getGridWidth(numTabs);
const numTabsWithOneSpacerEach = Math.floor(gridWidth / (tabWidth + tabSpacerWidth)); const numTabsWithOneSpacerEach = Math.floor(gridWidth / (tabWidth + tabSpacerWidth));
// But there is always one less spacer than tabs, so now check if an extra tab with one less spacer fits. // But there is always one less spacer than tabs, so now check if an extra tab with one less spacer fits.
@ -94,8 +80,12 @@ const getNumGridColumns = (numTabs: number) => {
return numTabsWithOneSpacerEach; return numTabsWithOneSpacerEach;
}; };
const getGridStyle = (side: string, numTabs: number = 0): CSSProperties => { const getGridStyle = (
const gridWidth = getGridWidth(numTabs); side: string,
numTabs: number = 0,
gridWidth: number,
expandedWidth: number
): CSSProperties => {
const relativePosition = Math.max(0, Math.floor(expandedWidth - gridWidth) / 2 - closeIconWidth); const relativePosition = Math.max(0, Math.floor(expandedWidth - gridWidth) / 2 - closeIconWidth);
return { return {
position: 'relative', position: 'relative',
@ -128,11 +118,53 @@ const getTabIconClassNames = (numTabs: number, isActiveTab: boolean) => {
rounded: isActiveTab, rounded: isActiveTab,
}); });
}; };
const createStyleMap = (
expandedWidth: number,
borderSize: number,
collapsedWidth: number
): StyleMap => {
const collapsedHideWidth = expandedWidth - collapsedWidth - borderSize;
return {
open: {
left: { marginLeft: '0px' },
right: { marginRight: '0px' },
},
closed: {
left: { marginLeft: `-${collapsedHideWidth}px` },
right: { marginRight: `-${collapsedHideWidth}px` },
},
};
};
const createBaseStyle = (expandedWidth: number) => {
return {
maxWidth: `${expandedWidth}px`,
width: `${expandedWidth}px`,
// To align the top of the side panel with the top of the viewport grid, use position relative and offset the
// top by the same top offset as the viewport grid. Also adjust the height so that there is no overflow.
position: 'relative',
top: '0.2%',
height: '99.8%',
};
};
const SidePanel = ({
side,
className,
activeTabIndex: activeTabIndexProp,
tabs,
onOpen,
expandedWidth = 248,
}) => {
const { t } = useTranslation('SidePanel');
const SidePanel = ({ side, className, activeTabIndex: activeTabIndexProp, tabs, onOpen }) => {
const [panelOpen, setPanelOpen] = useState(activeTabIndexProp !== null); const [panelOpen, setPanelOpen] = useState(activeTabIndexProp !== null);
const [activeTabIndex, setActiveTabIndex] = useState(0); const [activeTabIndex, setActiveTabIndex] = useState(0);
const styleMap = createStyleMap(expandedWidth, borderSize, collapsedWidth);
const baseStyle = createBaseStyle(expandedWidth);
const gridAvailableWidth = expandedWidth - closeIconWidth - gridHorizontalPadding;
const gridWidth = getGridWidth(tabs.length, gridAvailableWidth);
const openStatus = panelOpen ? 'open' : 'closed'; const openStatus = panelOpen ? 'open' : 'closed';
const style = Object.assign({}, styleMap[openStatus][side], baseStyle); const style = Object.assign({}, styleMap[openStatus][side], baseStyle);
@ -238,13 +270,13 @@ const SidePanel = ({ side, className, activeTabIndex: activeTabIndexProp, tabs,
}; };
const getTabGridComponent = () => { const getTabGridComponent = () => {
const numCols = getNumGridColumns(tabs.length); const numCols = getNumGridColumns(tabs.length, gridWidth);
return ( return (
<div className={classnames('flex grow ', side === 'right' ? 'justify-start' : 'justify-end')}> <div className={classnames('flex grow ', side === 'right' ? 'justify-start' : 'justify-end')}>
<div <div
className={classnames('bg-primary-dark text-primary-active flex flex-wrap')} className={classnames('bg-primary-dark text-primary-active flex flex-wrap')}
style={getGridStyle(side, tabs.length)} style={getGridStyle(side, tabs.length, gridWidth, expandedWidth)}
> >
{tabs.map((tab, tabIndex) => { {tabs.map((tab, tabIndex) => {
return ( return (
@ -360,6 +392,7 @@ SidePanel.propTypes = {
), ),
]), ]),
onOpen: PropTypes.func, onOpen: PropTypes.func,
expandedWidth: PropTypes.number,
}; };
export default SidePanel; export default SidePanel;