vitalCard.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import QuestionTooltip from 'sentry/components/questionTooltip';
  4. import {space} from 'sentry/styles/space';
  5. import {PERFORMANCE_SCORE_COLORS} from 'sentry/views/insights/browser/webVitals/utils/performanceScoreColors';
  6. type Props = {
  7. description: string;
  8. formattedValue: string | undefined;
  9. status: string | undefined;
  10. statusLabel: string | undefined;
  11. title: string;
  12. onClick?: () => void;
  13. };
  14. function VitalCard({
  15. description,
  16. formattedValue,
  17. status,
  18. statusLabel,
  19. title,
  20. onClick,
  21. }: Props) {
  22. return (
  23. <Fragment>
  24. <MeterBarContainer clickable={onClick !== undefined} onClick={onClick}>
  25. <MeterBarBody>
  26. {description && (
  27. <StyledQuestionTooltip
  28. isHoverable
  29. size="xs"
  30. title={<span>{description}</span>}
  31. />
  32. )}
  33. <MeterHeader>{title}</MeterHeader>
  34. <MeterValueText>{formattedValue ?? '-'}</MeterValueText>
  35. </MeterBarBody>
  36. <MeterBarFooter label={statusLabel} status={status} />
  37. </MeterBarContainer>
  38. </Fragment>
  39. );
  40. }
  41. const MeterBarContainer = styled('div')<{clickable?: boolean}>`
  42. flex: 1;
  43. position: relative;
  44. padding: 0;
  45. cursor: ${p => (p.clickable ? 'pointer' : 'default')};
  46. min-width: 140px;
  47. `;
  48. const MeterBarBody = styled('div')`
  49. border: 1px solid ${p => p.theme.gray200};
  50. border-radius: ${p => p.theme.borderRadius} ${p => p.theme.borderRadius} 0 0;
  51. border-bottom: none;
  52. padding: ${space(1)} 0 ${space(0.5)} 0;
  53. `;
  54. const MeterHeader = styled('div')`
  55. font-size: ${p => p.theme.fontSizeSmall};
  56. color: ${p => p.theme.textColor};
  57. display: inline-block;
  58. text-align: center;
  59. width: 100%;
  60. `;
  61. const MeterValueText = styled('div')`
  62. display: flex;
  63. justify-content: center;
  64. align-items: center;
  65. font-size: ${p => p.theme.headerFontSize};
  66. color: ${p => p.theme.textColor};
  67. flex: 1;
  68. text-align: center;
  69. `;
  70. function MeterBarFooter({
  71. label,
  72. status,
  73. }: {
  74. label: string | undefined;
  75. status: string | undefined;
  76. }) {
  77. return (
  78. <MeterBarFooterContainer status={status || 'none'}>
  79. {label || '-'}
  80. </MeterBarFooterContainer>
  81. );
  82. }
  83. const MeterBarFooterContainer = styled('div')<{status: string}>`
  84. color: ${p => p.theme[PERFORMANCE_SCORE_COLORS[p.status].normal]};
  85. border-radius: 0 0 ${p => p.theme.borderRadius} ${p => p.theme.borderRadius};
  86. background-color: ${p =>
  87. p.status === 'none' ? 'none' : p.theme[PERFORMANCE_SCORE_COLORS[p.status].light]};
  88. border: solid 1px ${p => p.theme[PERFORMANCE_SCORE_COLORS[p.status].light]};
  89. font-size: ${p => p.theme.fontSizeExtraSmall};
  90. padding: ${space(0.5)};
  91. text-align: center;
  92. `;
  93. const StyledQuestionTooltip = styled(QuestionTooltip)`
  94. position: absolute;
  95. right: ${space(1)};
  96. `;
  97. export default VitalCard;