settingsNavItem.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import type {ReactElement} from 'react';
  2. import {Fragment} from 'react';
  3. import {Link as RouterLink} from 'react-router';
  4. import styled from '@emotion/styled';
  5. import Badge from 'sentry/components/badge/badge';
  6. import FeatureBadge from 'sentry/components/badge/featureBadge';
  7. import HookOrDefault from 'sentry/components/hookOrDefault';
  8. import {Tooltip} from 'sentry/components/tooltip';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. type Props = {
  12. label: React.ReactNode;
  13. to: React.ComponentProps<RouterLink>['to'];
  14. badge?: string | number | null | ReactElement;
  15. id?: string;
  16. index?: boolean;
  17. onClick?: (e: React.MouseEvent) => void;
  18. };
  19. function SettingsNavItem({badge, label, index, id, ...props}: Props) {
  20. const LabelHook = HookOrDefault({
  21. hookName: 'sidebar:item-label',
  22. defaultComponent: ({children}) => <Fragment>{children}</Fragment>,
  23. });
  24. let renderedBadge: React.ReactNode;
  25. if (badge === 'new') {
  26. renderedBadge = <FeatureBadge type="new" />;
  27. } else if (badge === 'beta') {
  28. renderedBadge = <FeatureBadge type="beta" />;
  29. } else if (badge === 'warning') {
  30. renderedBadge = (
  31. <Tooltip title={t('This setting needs review')} position="right">
  32. <StyledBadge text={badge} type="warning" />
  33. </Tooltip>
  34. );
  35. } else if (typeof badge === 'string' || typeof badge === 'number') {
  36. renderedBadge = <StyledBadge text={badge} />;
  37. } else {
  38. renderedBadge = badge;
  39. }
  40. return (
  41. <StyledNavItem onlyActiveOnIndex={index} activeClassName="active" {...props}>
  42. <LabelHook id={id}>{label}</LabelHook>
  43. {badge ? renderedBadge : null}
  44. </StyledNavItem>
  45. );
  46. }
  47. const StyledNavItem = styled(RouterLink)`
  48. display: block;
  49. color: ${p => p.theme.gray300};
  50. font-size: 14px;
  51. line-height: 30px;
  52. position: relative;
  53. &.active {
  54. color: ${p => p.theme.textColor};
  55. &:before {
  56. background: ${p => p.theme.active};
  57. }
  58. }
  59. &:hover,
  60. &:focus,
  61. &:active {
  62. color: ${p => p.theme.textColor};
  63. outline: none;
  64. }
  65. &:focus-visible {
  66. outline: none;
  67. background: ${p => p.theme.backgroundSecondary};
  68. padding-left: 15px;
  69. margin-left: -15px;
  70. border-radius: 3px;
  71. &:before {
  72. left: -15px;
  73. }
  74. }
  75. &:before {
  76. position: absolute;
  77. content: '';
  78. display: block;
  79. top: 4px;
  80. left: -30px;
  81. height: 20px;
  82. width: 4px;
  83. background: transparent;
  84. border-radius: 0 2px 2px 0;
  85. }
  86. `;
  87. const StyledBadge = styled(Badge)`
  88. font-weight: 400;
  89. height: auto;
  90. line-height: 1;
  91. font-size: ${p => p.theme.fontSizeExtraSmall};
  92. padding: 3px ${space(0.75)};
  93. vertical-align: middle;
  94. `;
  95. export default SettingsNavItem;