You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by kg...@apache.org on 2024/03/04 11:14:15 UTC
(superset) branch master updated: feat: Responsive UI for Big Number with Time Comparison (#27375)
This is an automated email from the ASF dual-hosted git repository.
kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 5de2530e3c feat: Responsive UI for Big Number with Time Comparison (#27375)
5de2530e3c is described below
commit 5de2530e3cdc5799d08cfbad5871d24762a47ce4
Author: Kamil Gabryjelski <ka...@gmail.com>
AuthorDate: Mon Mar 4 12:14:09 2024 +0100
feat: Responsive UI for Big Number with Time Comparison (#27375)
---
.../BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx | 99 +++++++++++++++-------
.../BigNumberPeriodOverPeriod/controlPanel.ts | 8 +-
.../useOverflowDetection.ts | 63 ++++++++++++++
3 files changed, 138 insertions(+), 32 deletions(-)
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx
index 15d20707c1..4615341dfb 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { createRef, useMemo } from 'react';
+import React, { useMemo } from 'react';
import { css, styled, t, useTheme } from '@superset-ui/core';
import { Tooltip } from '@superset-ui/chart-controls';
import {
@@ -24,24 +24,33 @@ import {
PopKPIComparisonValueStyleProps,
PopKPIProps,
} from './types';
+import { useOverflowDetection } from './useOverflowDetection';
+
+const NumbersContainer = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ width: 100%;
+ overflow: auto;
+`;
const ComparisonValue = styled.div<PopKPIComparisonValueStyleProps>`
${({ theme, subheaderFontSize }) => `
font-weight: ${theme.typography.weights.light};
- width: 33%;
- display: table-cell;
+ display: flex;
+ justify-content: center;
font-size: ${subheaderFontSize || 20}px;
- text-align: center;
+ flex: 1 1 0px;
`}
`;
-const SymbolWrapper = styled.div<PopKPIComparisonSymbolStyleProps>`
+const SymbolWrapper = styled.span<PopKPIComparisonSymbolStyleProps>`
${({ theme, backgroundColor, textColor }) => `
background-color: ${backgroundColor};
color: ${textColor};
padding: ${theme.gridUnit}px ${theme.gridUnit * 2}px;
border-radius: ${theme.gridUnit * 2}px;
- display: inline-block;
margin-right: ${theme.gridUnit}px;
`}
`;
@@ -61,25 +70,23 @@ export default function PopKPI(props: PopKPIProps) {
comparatorText,
} = props;
- const rootElem = createRef<HTMLDivElement>();
const theme = useTheme();
-
+ const flexGap = theme.gridUnit * 5;
const wrapperDivStyles = css`
font-family: ${theme.typography.families.sansSerif};
- position: relative;
display: flex;
- flex-direction: column;
justify-content: center;
- padding: ${theme.gridUnit * 4}px;
- border-radius: ${theme.gridUnit * 2}px;
+ align-items: center;
height: ${height}px;
width: ${width}px;
+ overflow: auto;
`;
const bigValueContainerStyles = css`
font-size: ${headerFontSize || 60}px;
font-weight: ${theme.typography.weights.normal};
text-align: center;
+ margin-bottom: ${theme.gridUnit * 4}px;
`;
const getArrowIndicatorColor = () => {
@@ -135,29 +142,59 @@ export default function PopKPI(props: PopKPIProps) {
tooltipText: t('Percentage difference between the time periods'),
},
],
- [prevNumber, valueDifference, percentDifferenceFormattedString],
+ [
+ comparatorText,
+ prevNumber,
+ valueDifference,
+ percentDifferenceFormattedString,
+ ],
);
+ const { isOverflowing, symbolContainerRef, wrapperRef } =
+ useOverflowDetection(flexGap);
+
return (
- <div ref={rootElem} css={wrapperDivStyles}>
- <div css={bigValueContainerStyles}>
- {bigNumber}
- {percentDifferenceNumber !== 0 && (
- <span css={arrowIndicatorStyle}>
- {percentDifferenceNumber > 0 ? '↑' : '↓'}
- </span>
- )}
- </div>
- <div
- css={css`
- width: 100%;
- display: table;
- `}
+ <div css={wrapperDivStyles} ref={wrapperRef}>
+ <NumbersContainer
+ css={
+ isOverflowing &&
+ css`
+ width: fit-content;
+ margin: auto;
+ align-items: flex-start;
+ `
+ }
>
+ <div css={bigValueContainerStyles}>
+ {bigNumber}
+ {percentDifferenceNumber !== 0 && (
+ <span css={arrowIndicatorStyle}>
+ {percentDifferenceNumber > 0 ? '↑' : '↓'}
+ </span>
+ )}
+ </div>
+
<div
- css={css`
- display: table-row;
- `}
+ css={[
+ css`
+ display: flex;
+ justify-content: space-around;
+ gap: ${flexGap}px;
+ min-width: 0;
+ flex-shrink: 1;
+ `,
+ isOverflowing
+ ? css`
+ flex-direction: column;
+ align-items: flex-start;
+ width: fit-content;
+ `
+ : css`
+ align-items: center;
+ width: 100%;
+ `,
+ ]}
+ ref={symbolContainerRef}
>
{SYMBOLS_WITH_VALUES.map((symbol_with_value, index) => (
<ComparisonValue
@@ -182,7 +219,7 @@ export default function PopKPI(props: PopKPIProps) {
</ComparisonValue>
))}
</div>
- </div>
+ </NumbersContainer>
</div>
);
}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts
index 5e7fb8af2f..5ac80eaf96 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts
@@ -103,12 +103,18 @@ const config: ControlPanelConfig = {
controlSetRows: [
['y_axis_format'],
['currency_format'],
- [headerFontSize],
+ [
+ {
+ ...headerFontSize,
+ config: { ...headerFontSize.config, default: 0.2 },
+ },
+ ],
[
{
...subheaderFontSize,
config: {
...subheaderFontSize.config,
+ default: 0.125,
label: t('Comparison font size'),
},
},
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/useOverflowDetection.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/useOverflowDetection.ts
new file mode 100644
index 0000000000..42cda225d3
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/useOverflowDetection.ts
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useEffect, useRef, useState } from 'react';
+import { debounce } from 'lodash';
+
+export const useOverflowDetection = (flexGap: number) => {
+ const symbolContainerRef = useRef<HTMLDivElement>(null);
+ const wrapperRef = useRef<HTMLDivElement>(null);
+ const [isOverflowing, setIsOverflowing] = useState(false);
+
+ useEffect(() => {
+ let obs: ResizeObserver;
+ const symbolContainerElem = symbolContainerRef.current;
+ const wrapperElem = wrapperRef.current;
+ if (symbolContainerElem && wrapperElem) {
+ const symbolContainerChildrenElems = Array.from(
+ symbolContainerElem.children,
+ );
+ obs = new ResizeObserver(
+ debounce(() => {
+ const totalChildrenWidth = symbolContainerChildrenElems.reduce(
+ (acc, element) =>
+ // take symbol container's child's scroll width to account for the container growing with display: flex
+ acc + (element.firstElementChild?.scrollWidth ?? 0),
+ 0,
+ );
+ if (
+ totalChildrenWidth +
+ flexGap * Math.max(symbolContainerChildrenElems.length - 1, 0) >
+ wrapperElem.clientWidth
+ ) {
+ setIsOverflowing(true);
+ } else {
+ setIsOverflowing(false);
+ }
+ }, 500),
+ );
+ obs.observe(document.body);
+ symbolContainerChildrenElems.forEach(elem => {
+ obs.observe(elem);
+ });
+ }
+ return () => obs?.disconnect();
+ }, [flexGap]);
+
+ return { isOverflowing, symbolContainerRef, wrapperRef };
+};