mirror of
https://github.com/FranP-code/spend-ia.git
synced 2025-10-13 00:14:09 +00:00
feat: legend
This commit is contained in:
@@ -40,6 +40,16 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
|
'react/jsx-sort-props': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
callbacksLast: true,
|
||||||
|
ignoreCase: true,
|
||||||
|
noSortAlphabetically: false,
|
||||||
|
reservedFirst: true,
|
||||||
|
shorthandFirst: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
'sort-keys-fix/sort-keys-fix': 'error',
|
'sort-keys-fix/sort-keys-fix': 'error',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,54 +3,78 @@ import Chart from 'react-google-charts';
|
|||||||
import styled, { useTheme } from 'styled-components';
|
import styled, { useTheme } from 'styled-components';
|
||||||
import { type Theme } from '@/lib/theme';
|
import { type Theme } from '@/lib/theme';
|
||||||
import { type PieCircleData } from '@/lib/types';
|
import { type PieCircleData } from '@/lib/types';
|
||||||
|
import { capitalize } from '@/lib/utils';
|
||||||
|
|
||||||
export const PieCircle = (props: { pieCircleData: PieCircleData }): JSX.Element => {
|
export const PieCircle = (props: { pieCircleData: PieCircleData }): JSX.Element => {
|
||||||
const { pieCircleData } = props;
|
const { pieCircleData } = props;
|
||||||
const theme = useTheme() as Theme;
|
const theme = useTheme() as Theme;
|
||||||
const { colors } = theme;
|
const { colors } = theme;
|
||||||
|
const height = '400px';
|
||||||
const [data, legendData, chartColors] = [
|
const [data, legendData, chartColors] = [
|
||||||
pieCircleData.map(([[label, value]]) => [label, parseFloat(value.toFixed(2))]),
|
pieCircleData.map(([[label, value]]) => [capitalize(label), parseFloat(value.toFixed(2))]),
|
||||||
pieCircleData.map(([, item]) => item),
|
pieCircleData.sort(([[, a]], [[, b]]) => b - a).map(([, item]) => item),
|
||||||
pieCircleData.map(([, { backgroundColor }]) => backgroundColor),
|
pieCircleData.map(([, { backgroundColor }]) => backgroundColor),
|
||||||
];
|
];
|
||||||
|
console.log({ data, legendData });
|
||||||
return (
|
return (
|
||||||
<PieCircleContainer>
|
<PieCircleContainer>
|
||||||
|
<ChartContainer height={height}>
|
||||||
<StyledChart
|
<StyledChart
|
||||||
chartType="PieChart"
|
chartType="PieChart"
|
||||||
data={[['X', 'Y'], ...data]}
|
data={[['X', 'Y'], ...data]}
|
||||||
|
height={height}
|
||||||
options={{
|
options={{
|
||||||
backgroundColor: colors.primary,
|
backgroundColor: colors.primary,
|
||||||
colors: chartColors,
|
colors: chartColors,
|
||||||
legend: 'none',
|
legend: 'none',
|
||||||
|
pieHole: 0.4,
|
||||||
}}
|
}}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
height={'400px'}
|
|
||||||
/>
|
/>
|
||||||
<div>
|
</ChartContainer>
|
||||||
{legendData.map(({ backgroundColor, label }) => (
|
<LegendContainer>
|
||||||
<>
|
{legendData.map(({ backgroundColor, label }, index) => (
|
||||||
<div
|
<LegendItem key={`${index as number}-label`}>
|
||||||
style={{
|
<LegendColor color={backgroundColor} />
|
||||||
backgroundColor,
|
<LegendLabel>{label}</LegendLabel>
|
||||||
borderRadius: '100%',
|
</LegendItem>
|
||||||
height: '20px',
|
|
||||||
width: '20px',
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
color: '#fff',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</LegendContainer>
|
||||||
</PieCircleContainer>
|
</PieCircleContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ChartContainer = styled.div<{ height: string }>`
|
||||||
|
height: ${({ height }) => height};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LegendContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LegendColor = styled.div<{ color: string }>`
|
||||||
|
background-color: ${({ color }) => color};
|
||||||
|
border: 1px solid #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 25px;
|
||||||
|
max-width: 200px;
|
||||||
|
min-width: 50px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LegendItem = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LegendLabel = styled.span<{ theme: Theme }>`
|
||||||
|
color: ${({ theme }) => theme.colors.textColor.primary};
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 3px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
`;
|
||||||
|
|
||||||
const PieCircleContainer = styled.div`
|
const PieCircleContainer = styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const theme: Theme = {
|
|||||||
secondary: '#443C68',
|
secondary: '#443C68',
|
||||||
complementary: '#393053',
|
complementary: '#393053',
|
||||||
textColor: {
|
textColor: {
|
||||||
primary: '#ddd',
|
primary: '#fff',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
1
packages/client/lib/utils.ts
Normal file
1
packages/client/lib/utils.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const capitalize = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
@@ -12,8 +12,8 @@ export const Header = (): JSX.Element => {
|
|||||||
<TabsContainer>
|
<TabsContainer>
|
||||||
{tabs.map((tabData) => (
|
{tabs.map((tabData) => (
|
||||||
<StyledTab
|
<StyledTab
|
||||||
active={tab.id === tabData.id}
|
|
||||||
key={tabData.id}
|
key={tabData.id}
|
||||||
|
active={tab.id === tabData.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTab(tabData);
|
setTab(tabData);
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user