scoreCard.tsx 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. import {Panel} from 'app/components/panels';
  4. import QuestionTooltip from 'app/components/questionTooltip';
  5. import TextOverflow from 'app/components/textOverflow';
  6. import overflowEllipsis from 'app/styles/overflowEllipsis';
  7. import space from 'app/styles/space';
  8. import {defined} from 'app/utils';
  9. import {Theme} from 'app/utils/theme';
  10. type Props = {
  11. title: React.ReactNode;
  12. score?: React.ReactNode;
  13. help?: React.ReactNode;
  14. trend?: React.ReactNode;
  15. trendStatus?: 'good' | 'bad';
  16. className?: string;
  17. };
  18. function ScoreCard({title, score, help, trend, trendStatus, className}: Props) {
  19. return (
  20. <StyledPanel className={className}>
  21. <HeaderTitle>
  22. <Title>{title}</Title>
  23. {help && <QuestionTooltip title={help} size="sm" position="top" />}
  24. </HeaderTitle>
  25. <ScoreWrapper>
  26. <Score>{score ?? '\u2014'}</Score>
  27. {defined(trend) && (
  28. <Trend trendStatus={trendStatus}>
  29. <TextOverflow>{trend}</TextOverflow>
  30. </Trend>
  31. )}
  32. </ScoreWrapper>
  33. </StyledPanel>
  34. );
  35. }
  36. function getTrendColor(p: TrendProps & {theme: Theme}) {
  37. switch (p.trendStatus) {
  38. case 'good':
  39. return p.theme.green300;
  40. case 'bad':
  41. return p.theme.red300;
  42. default:
  43. return p.theme.gray300;
  44. }
  45. }
  46. const StyledPanel = styled(Panel)`
  47. display: flex;
  48. flex-direction: column;
  49. justify-content: space-between;
  50. padding: ${space(2)} ${space(3)};
  51. min-height: 96px;
  52. `;
  53. const HeaderTitle = styled('div')`
  54. display: inline-grid;
  55. grid-auto-flow: column;
  56. grid-gap: ${space(1)};
  57. align-items: center;
  58. width: fit-content;
  59. `;
  60. const Title = styled('div')`
  61. ${overflowEllipsis};
  62. `;
  63. const ScoreWrapper = styled('div')`
  64. display: flex;
  65. flex-direction: row;
  66. align-items: flex-end;
  67. max-width: 100%;
  68. `;
  69. const Score = styled('span')`
  70. flex-shrink: 1;
  71. font-size: 32px;
  72. line-height: 1;
  73. white-space: nowrap;
  74. `;
  75. type TrendProps = {trendStatus: Props['trendStatus']};
  76. const Trend = styled('div')<TrendProps>`
  77. color: ${getTrendColor};
  78. margin-left: ${space(1)};
  79. line-height: 1;
  80. overflow: hidden;
  81. `;
  82. export default ScoreCard;