settingsPageHeader.tsx 2.9 KB

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