Fix and improve chart type selection (#16033)
The new version of the side panel is smaller so it introduced a regression on the chart type selection because there was not enough space for all the chart types to fit with the label. This PR removes the label to gain some space and display the chart type label in a tooltip. ## Before <img width="834" height="1406" alt="CleanShot 2025-11-24 at 17 33 45@2x" src="https://github.com/user-attachments/assets/76bbea54-af16-4643-9de6-ab3da6741e11" /> ## After ### Without disabled charts https://github.com/user-attachments/assets/74d62b86-e440-41f5-a3e6-c5754940c28e ### With disabled charts https://github.com/user-attachments/assets/f4ce3a3a-5dee-4f41-8b96-5f671794197d
This commit is contained in:
+4
-3
@@ -47,17 +47,18 @@ export const ChartTypeSelectionSection = ({
|
||||
|
||||
return (
|
||||
<MenuPicker
|
||||
id={graphType}
|
||||
selected={currentGraphType === graphType}
|
||||
key={graphType}
|
||||
icon={GRAPH_TYPE_INFORMATION[graphType].icon}
|
||||
onClick={() => {
|
||||
setCurrentGraphType(graphType);
|
||||
}}
|
||||
label={
|
||||
isDisabled ? t`Soon` : t(GRAPH_TYPE_INFORMATION[graphType].label)
|
||||
}
|
||||
showLabel
|
||||
disabled={isDisabled}
|
||||
tooltipContent={
|
||||
isDisabled ? t`Soon` : t(GRAPH_TYPE_INFORMATION[graphType].label)
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
+6
-6
@@ -26,32 +26,32 @@ export const GRAPH_TYPE_INFORMATION: Record<
|
||||
}
|
||||
> = {
|
||||
[GraphType.VERTICAL_BAR]: {
|
||||
label: msg`Vertical`,
|
||||
label: msg`Vertical Bar Chart`,
|
||||
icon: IconChartBar,
|
||||
settings: getBarChartSettings(GraphType.VERTICAL_BAR),
|
||||
},
|
||||
[GraphType.HORIZONTAL_BAR]: {
|
||||
label: msg`Horizontal`,
|
||||
label: msg`Horizontal Bar Chart`,
|
||||
icon: IconChartBarHorizontal,
|
||||
settings: getBarChartSettings(GraphType.HORIZONTAL_BAR),
|
||||
},
|
||||
[GraphType.PIE]: {
|
||||
label: msg`Pie`,
|
||||
label: msg`Pie Chart`,
|
||||
icon: IconChartPie,
|
||||
settings: PIE_CHART_SETTINGS,
|
||||
},
|
||||
[GraphType.LINE]: {
|
||||
label: msg`Line`,
|
||||
label: msg`Line Chart`,
|
||||
icon: IconChartLine,
|
||||
settings: LINE_CHART_SETTINGS,
|
||||
},
|
||||
[GraphType.AGGREGATE]: {
|
||||
label: msg`Aggregate`,
|
||||
label: msg`Aggregate Chart`,
|
||||
icon: IconSum,
|
||||
settings: AGGREGATE_CHART_SETTINGS,
|
||||
},
|
||||
[GraphType.GAUGE]: {
|
||||
label: msg`Gauge`,
|
||||
label: msg`Gauge Chart`,
|
||||
icon: IconGauge,
|
||||
settings: GAUGE_CHART_SETTINGS,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
IconAlertTriangle,
|
||||
IconInfoCircle,
|
||||
@@ -66,7 +67,7 @@ export const SidePanelInformationBanner = ({
|
||||
)}
|
||||
</StyledIconContainer>
|
||||
<StyledMessage>{message}</StyledMessage>
|
||||
{tooltipMessage && (
|
||||
{isDefined(tooltipMessage) && (
|
||||
<AppTooltip
|
||||
anchorSelect={`[data-tooltip-id='${tooltipId}']`}
|
||||
content={tooltipMessage}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { type IconComponent } from '@ui/display';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
AppTooltip,
|
||||
TooltipDelay,
|
||||
TooltipPosition,
|
||||
type IconComponent,
|
||||
} from '@ui/display';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledMenuPicker = styled.button<{
|
||||
selected: boolean;
|
||||
@@ -101,17 +108,22 @@ const StyledLabel = styled.div<{
|
||||
`;
|
||||
|
||||
export type MenuPickerProps = {
|
||||
id: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
icon: IconComponent;
|
||||
label: string;
|
||||
label?: string;
|
||||
onClick?: () => void;
|
||||
selected?: boolean;
|
||||
showLabel?: boolean;
|
||||
testId?: string;
|
||||
tooltipContent?: string;
|
||||
tooltipDelay?: TooltipDelay;
|
||||
tooltipOffset?: number;
|
||||
};
|
||||
|
||||
export const MenuPicker = ({
|
||||
id,
|
||||
icon: Icon,
|
||||
label,
|
||||
selected = false,
|
||||
@@ -120,29 +132,47 @@ export const MenuPicker = ({
|
||||
onClick,
|
||||
className,
|
||||
testId,
|
||||
tooltipContent,
|
||||
tooltipDelay = TooltipDelay.noDelay,
|
||||
tooltipOffset = 5,
|
||||
}: MenuPickerProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuPicker
|
||||
selected={selected}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
data-testid={testId}
|
||||
aria-pressed={selected}
|
||||
aria-disabled={disabled}
|
||||
aria-label={label}
|
||||
>
|
||||
<StyledIconContainer>
|
||||
<Icon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
|
||||
</StyledIconContainer>
|
||||
<>
|
||||
<StyledMenuPicker
|
||||
id={id}
|
||||
selected={selected}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
data-testid={testId}
|
||||
aria-pressed={selected}
|
||||
aria-disabled={disabled}
|
||||
aria-label={label}
|
||||
>
|
||||
<StyledIconContainer>
|
||||
<Icon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} />
|
||||
</StyledIconContainer>
|
||||
|
||||
{showLabel && (
|
||||
<StyledLabel selected={selected} disabled={disabled}>
|
||||
{label}
|
||||
</StyledLabel>
|
||||
{isDefined(label) && showLabel && (
|
||||
<StyledLabel selected={selected} disabled={disabled}>
|
||||
{label}
|
||||
</StyledLabel>
|
||||
)}
|
||||
</StyledMenuPicker>
|
||||
|
||||
{isNonEmptyString(tooltipContent) && (
|
||||
<AppTooltip
|
||||
anchorSelect={`#${id}`}
|
||||
offset={tooltipOffset}
|
||||
content={tooltipContent}
|
||||
place={TooltipPosition.Bottom}
|
||||
positionStrategy="fixed"
|
||||
delay={tooltipDelay}
|
||||
noArrow
|
||||
/>
|
||||
)}
|
||||
</StyledMenuPicker>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+30
-5
@@ -1,6 +1,6 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
import { IconChartPie } from '@ui/display';
|
||||
import { IconChartPie, TooltipDelay } from '@ui/display';
|
||||
import { MenuPicker } from '@ui/navigation/menu/components/MenuPicker';
|
||||
import { ComponentDecorator } from '@ui/testing';
|
||||
|
||||
@@ -67,19 +67,44 @@ export const AllStates: Story = {
|
||||
>
|
||||
<div>
|
||||
<StyledTitle>Default</StyledTitle>
|
||||
<MenuPicker icon={IconChartPie} label="Default" />
|
||||
<MenuPicker id="default" icon={IconChartPie} label="Default" />
|
||||
</div>
|
||||
<div>
|
||||
<StyledTitle>Selected</StyledTitle>
|
||||
<MenuPicker icon={IconChartPie} label="Selected" selected />
|
||||
<MenuPicker
|
||||
id="selected"
|
||||
icon={IconChartPie}
|
||||
label="Selected"
|
||||
selected
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<StyledTitle>Disabled</StyledTitle>
|
||||
<MenuPicker icon={IconChartPie} label="Disabled" disabled />
|
||||
<MenuPicker
|
||||
id="disabled"
|
||||
icon={IconChartPie}
|
||||
label="Disabled"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<StyledTitle>No Label</StyledTitle>
|
||||
<MenuPicker icon={IconChartPie} label="No Label" showLabel={false} />
|
||||
<MenuPicker
|
||||
id="no-label"
|
||||
icon={IconChartPie}
|
||||
label="No Label"
|
||||
showLabel={false}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<StyledTitle> With Tooltip</StyledTitle>
|
||||
<MenuPicker
|
||||
id="tooltip"
|
||||
icon={IconChartPie}
|
||||
label="Tooltip"
|
||||
tooltipContent="Tooltip"
|
||||
tooltipDelay={TooltipDelay.mediumDelay}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user