helpSearch.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import * as React from 'react';
  2. import styled from '@emotion/styled';
  3. import {Search} from 'sentry/components/search';
  4. import SearchResult from 'sentry/components/search/searchResult';
  5. import SearchResultWrapper from 'sentry/components/search/searchResultWrapper';
  6. import HelpSource from 'sentry/components/search/sources/helpSource';
  7. import {IconWindow} from 'sentry/icons';
  8. import {t, tn} from 'sentry/locale';
  9. import space from 'sentry/styles/space';
  10. type HelpResult = Parameters<
  11. React.ComponentProps<typeof HelpSource>['children']
  12. >[0]['results'][0];
  13. type ResultItemProps = HelpResult & {
  14. highlighted: boolean;
  15. // TODO(ts): Improve types when we've typed more of the search components
  16. itemProps: any;
  17. };
  18. const renderResult = ({item, matches, itemProps, highlighted}: ResultItemProps) => {
  19. const sectionHeading =
  20. item.sectionHeading !== undefined ? (
  21. <SectionHeading>
  22. <IconWindow />
  23. {t('From %s', item.sectionHeading)}
  24. <Count>{tn('%s result', '%s results', item.sectionCount ?? 0)}</Count>
  25. </SectionHeading>
  26. ) : null;
  27. if (item.empty) {
  28. return (
  29. <React.Fragment>
  30. {sectionHeading}
  31. <Empty>{t('No results from %s', item.sectionHeading)}</Empty>
  32. </React.Fragment>
  33. );
  34. }
  35. return (
  36. <React.Fragment>
  37. {sectionHeading}
  38. <SearchResultWrapper {...itemProps} highlighted={highlighted}>
  39. <SearchResult highlighted={highlighted} item={item} matches={matches} />
  40. </SearchResultWrapper>
  41. </React.Fragment>
  42. );
  43. };
  44. // TODO(ts): Type based on Search props once that has types
  45. const HelpSearch = props => (
  46. <Search
  47. {...props}
  48. sources={[HelpSource]}
  49. minSearch={3}
  50. closeOnSelect={false}
  51. renderItem={renderResult}
  52. />
  53. );
  54. const SectionHeading = styled('div')`
  55. display: grid;
  56. grid-template-columns: max-content 1fr max-content;
  57. gap: ${space(1)};
  58. align-items: center;
  59. background: ${p => p.theme.backgroundSecondary};
  60. padding: ${space(1)} ${space(2)};
  61. &:not(:first-of-type) {
  62. border-top: 1px solid ${p => p.theme.innerBorder};
  63. }
  64. `;
  65. const Count = styled('div')`
  66. font-size: ${p => p.theme.fontSizeSmall};
  67. color: ${p => p.theme.gray300};
  68. `;
  69. const Empty = styled('div')`
  70. display: flex;
  71. align-items: center;
  72. padding: ${space(2)};
  73. color: ${p => p.theme.subText};
  74. font-size: ${p => p.theme.fontSizeMedium};
  75. border-top: 1px solid ${p => p.theme.innerBorder};
  76. `;
  77. export default HelpSearch;