layout.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import {ComponentProps, Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import HookOrDefault from 'sentry/components/hookOrDefault';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import List from 'sentry/components/list';
  6. import ListItem from 'sentry/components/list/listItem';
  7. import {Step, StepProps} from 'sentry/components/onboarding/gettingStartedDoc/step';
  8. import {PlatformOptionsControl} from 'sentry/components/onboarding/platformOptionsControl';
  9. import {ProductSelection} from 'sentry/components/onboarding/productSelection';
  10. import {PlatformKey} from 'sentry/data/platformCategories';
  11. import {t} from 'sentry/locale';
  12. import {space} from 'sentry/styles/space';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. const ProductSelectionAvailabilityHook = HookOrDefault({
  15. hookName: 'component:product-selection-availability',
  16. defaultComponent: ProductSelection,
  17. });
  18. type NextStep = {
  19. description: string;
  20. link: string;
  21. name: string;
  22. };
  23. export type LayoutProps = {
  24. steps: StepProps[];
  25. /**
  26. * An introduction displayed before the steps
  27. */
  28. introduction?: React.ReactNode;
  29. newOrg?: boolean;
  30. nextSteps?: NextStep[];
  31. platformKey?: PlatformKey;
  32. platformOptions?: ComponentProps<typeof PlatformOptionsControl>['platformOptions'];
  33. };
  34. export function Layout({
  35. steps,
  36. platformKey,
  37. newOrg,
  38. nextSteps = [],
  39. platformOptions,
  40. introduction,
  41. }: LayoutProps) {
  42. const organization = useOrganization();
  43. return (
  44. <Wrapper>
  45. {introduction && <Introduction>{introduction}</Introduction>}
  46. <ProductSelectionAvailabilityHook
  47. organization={organization}
  48. platform={platformKey}
  49. />
  50. {platformOptions ? (
  51. <PlatformOptionsControl platformOptions={platformOptions} />
  52. ) : null}
  53. <Divider withBottomMargin={newOrg} />
  54. <Steps>
  55. {steps.map(step => (
  56. <Step key={step.title ?? step.type} {...step} />
  57. ))}
  58. </Steps>
  59. {nextSteps.length > 0 && (
  60. <Fragment>
  61. <Divider />
  62. <h4>{t('Next Steps')}</h4>
  63. <List symbol="bullet">
  64. {nextSteps.map(step => (
  65. <ListItem key={step.name}>
  66. <ExternalLink href={step.link}>{step.name}</ExternalLink>
  67. {': '}
  68. {step.description}
  69. </ListItem>
  70. ))}
  71. </List>
  72. </Fragment>
  73. )}
  74. </Wrapper>
  75. );
  76. }
  77. const Divider = styled('hr')<{withBottomMargin?: boolean}>`
  78. height: 1px;
  79. width: 100%;
  80. background: ${p => p.theme.border};
  81. border: none;
  82. ${p => p.withBottomMargin && `margin-bottom: ${space(3)}`}
  83. `;
  84. const Steps = styled('div')`
  85. display: flex;
  86. flex-direction: column;
  87. gap: 1.5rem;
  88. `;
  89. const Introduction = styled('div')`
  90. display: flex;
  91. flex-direction: column;
  92. gap: ${space(1)};
  93. padding-bottom: ${space(2)};
  94. `;
  95. const Wrapper = styled('div')`
  96. h4 {
  97. margin-bottom: 0.5em;
  98. }
  99. && {
  100. p {
  101. margin-bottom: 0;
  102. }
  103. h5 {
  104. margin-bottom: 0;
  105. }
  106. }
  107. `;