scoreCard.tsx 2.3 KB

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