item.tsx 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import {lazy, Suspense} from 'react';
  2. import styled from '@emotion/styled';
  3. import LoadingMask from 'sentry/components/loadingMask';
  4. import {space} from 'sentry/styles/space';
  5. type Props = {
  6. children: React.ReactNode;
  7. /**
  8. * An icon may be passed as a string name which will be dynamically with a
  9. * ContextIcon or a react node will simply render.
  10. */
  11. icon?: string | React.ReactElement;
  12. };
  13. const ContextIcon = lazy(() => import('./contextIcon'));
  14. function Item({children, icon = 'unknown'}: Props) {
  15. // XXX: Codesplit the ContextIcon component since it packs a lot of SVGs
  16. const iconNode =
  17. typeof icon === 'string' ? (
  18. <Suspense fallback={<LoadingMask />}>
  19. <ContextIcon name={icon} />
  20. </Suspense>
  21. ) : (
  22. icon
  23. );
  24. return (
  25. <ItemContainer data-test-id="context-item">
  26. <IconContainer>{iconNode}</IconContainer>
  27. {children && <Details>{children}</Details>}
  28. </ItemContainer>
  29. );
  30. }
  31. export default Item;
  32. const Details = styled('div')`
  33. display: flex;
  34. flex-direction: column;
  35. justify-content: center;
  36. min-height: 48px;
  37. min-width: 0;
  38. `;
  39. const IconContainer = styled('div')`
  40. width: 36px;
  41. height: 36px;
  42. display: flex;
  43. flex-shrink: 0;
  44. align-items: center;
  45. justify-content: center;
  46. `;
  47. const ItemContainer = styled('div')`
  48. position: relative;
  49. display: flex;
  50. gap: ${space(1)};
  51. align-items: center;
  52. max-width: 25%;
  53. h3 {
  54. ${p => p.theme.overflowEllipsis}
  55. font-size: ${p => p.theme.fontSizeLarge};
  56. margin-bottom: ${space(0.25)};
  57. }
  58. p {
  59. font-size: ${p => p.theme.fontSizeSmall};
  60. &:last-child {
  61. margin: 0;
  62. }
  63. }
  64. @media (max-width: ${p => p.theme.breakpoints.small}) {
  65. max-width: initial;
  66. padding-top: ${space(0.5)};
  67. padding-bottom: ${space(0.5)};
  68. :not(:first-child) {
  69. border-top: 1px solid ${p => p.theme.innerBorder};
  70. }
  71. }
  72. `;