settingsPageHeader.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import styled from '@emotion/styled';
  2. import * as Layout from 'sentry/components/layouts/thirds';
  3. import {space} from 'sentry/styles/space';
  4. type Props = {
  5. /**
  6. * The page title
  7. */
  8. title: React.ReactNode;
  9. /**
  10. * A CTA Button
  11. */
  12. action?: React.ReactNode;
  13. body?: React.ReactNode;
  14. className?: string;
  15. /**
  16. * Use a purple color for the subtitle
  17. */
  18. colorSubtitle?: boolean;
  19. /**
  20. * Icon to the left of the title
  21. */
  22. icon?: React.ReactNode;
  23. /**
  24. * Disables font styles in the title. Allows for more custom titles.
  25. */
  26. noTitleStyles?: boolean;
  27. subtitle?: React.ReactNode;
  28. tabs?: React.ReactNode;
  29. };
  30. function UnstyledSettingsPageHeader({
  31. icon,
  32. title,
  33. subtitle,
  34. colorSubtitle,
  35. action,
  36. body,
  37. tabs,
  38. noTitleStyles = false,
  39. ...props
  40. }: Props) {
  41. // If Header is narrow, use align-items to center <Action>.
  42. // Otherwise, use a fixed margin to prevent an odd alignment.
  43. // This is needed as Actions could be a button or a dropdown.
  44. const isNarrow = !subtitle;
  45. return (
  46. <div {...props}>
  47. <TitleAndActions isNarrow={isNarrow}>
  48. <TitleWrapper>
  49. {icon && <Icon>{icon}</Icon>}
  50. {title && (
  51. <Title tabs={tabs} styled={noTitleStyles}>
  52. <Layout.Title>{title}</Layout.Title>
  53. {subtitle && <Subtitle colorSubtitle={colorSubtitle}>{subtitle}</Subtitle>}
  54. </Title>
  55. )}
  56. </TitleWrapper>
  57. {action && <Action isNarrow={isNarrow}>{action}</Action>}
  58. </TitleAndActions>
  59. {body && <BodyWrapper>{body}</BodyWrapper>}
  60. {tabs && <TabsWrapper>{tabs}</TabsWrapper>}
  61. </div>
  62. );
  63. }
  64. interface TitleProps extends React.HTMLAttributes<HTMLDivElement> {
  65. styled?: boolean;
  66. tabs?: React.ReactNode;
  67. }
  68. const TitleAndActions = styled('div')<{isNarrow?: boolean}>`
  69. display: flex;
  70. align-items: ${p => (p.isNarrow ? 'center' : 'flex-start')};
  71. `;
  72. const TitleWrapper = styled('div')`
  73. flex: 1;
  74. `;
  75. const Title = styled('div')<TitleProps>`
  76. ${p => !p.styled && `font-size: 20px; font-weight: ${p.theme.fontWeightBold};`};
  77. margin: ${space(4)} ${space(2)} ${space(3)} 0;
  78. `;
  79. const Subtitle = styled('div')<{colorSubtitle?: boolean}>`
  80. color: ${p => (p.colorSubtitle ? p.theme.purple400 : p.theme.gray400)};
  81. font-weight: ${p => p.theme.fontWeightNormal};
  82. font-size: ${p => p.theme.fontSizeLarge};
  83. padding: ${space(1.5)} 0 0;
  84. `;
  85. const Icon = styled('div')`
  86. margin-right: ${space(1)};
  87. `;
  88. const Action = styled('div')<{isNarrow?: boolean}>`
  89. margin-top: ${p => (p.isNarrow ? '0' : space(4))};
  90. `;
  91. const SettingsPageHeader = styled(UnstyledSettingsPageHeader)<
  92. Omit<React.HTMLProps<HTMLDivElement>, keyof Props> & Props
  93. >`
  94. font-size: 14px;
  95. margin-top: -${space(4)};
  96. `;
  97. const BodyWrapper = styled('div')`
  98. flex: 1;
  99. margin: 0 0 ${space(3)};
  100. `;
  101. const TabsWrapper = styled('div')`
  102. flex: 1;
  103. margin: 0; /* sentry/components/navTabs has added margin */
  104. `;
  105. export default SettingsPageHeader;