settingsPageHeader.tsx 2.6 KB

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